parallel_tests 3.7.3 → 4.7.2

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,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 = "#{executable} -Itest -e '%w[#{require_list}].each { |f| require %{./\#{f}} }' -- #{options[:test_options]}"
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" => test_env_number(process_number, options).to_s,
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 #{cmd}" if options[:nice]
85
- cmd = "#{cmd} 2>&1" if options[:combine_stderr]
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
- puts cmd if report_process_command?(options) && !options[:serialize_stdout]
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 = [cmd, output].join("\n") if report_process_command?(options) && options[:serialize_stdout]
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.sub(/\s--seed\s+\d+\b/, '')
133
- "#{clean} --seed #{seed}"
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'] || determine_executable
160
+ if (executable = ENV['PARALLEL_TESTS_EXECUTABLE'])
161
+ Shellwords.shellsplit(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
@@ -213,8 +238,9 @@ module ParallelTests
213
238
  suffix_pattern = options[:suffix] || test_suffix
214
239
  include_pattern = options[:pattern] || //
215
240
  exclude_pattern = options[:exclude_pattern]
241
+ allow_duplicates = options[:allow_duplicates]
216
242
 
217
- (tests || []).flat_map do |file_or_folder|
243
+ files = (tests || []).flat_map do |file_or_folder|
218
244
  if File.directory?(file_or_folder)
219
245
  files = files_in_folder(file_or_folder, options)
220
246
  files = files.grep(suffix_pattern).grep(include_pattern)
@@ -223,7 +249,9 @@ module ParallelTests
223
249
  else
224
250
  file_or_folder
225
251
  end
226
- end.uniq
252
+ end
253
+
254
+ allow_duplicates ? files : files.uniq
227
255
  end
228
256
 
229
257
  def files_in_folder(folder, options = {})
@@ -237,6 +265,21 @@ module ParallelTests
237
265
  Dir[File.join(folder, pattern)].uniq.sort
238
266
  end
239
267
 
268
+ def remove_command_arguments(command, *args)
269
+ remove_next = false
270
+ command.select do |arg|
271
+ if remove_next
272
+ remove_next = false
273
+ false
274
+ elsif args.include?(arg)
275
+ remove_next = true
276
+ false
277
+ else
278
+ true
279
+ end
280
+ end
281
+ end
282
+
240
283
  private
241
284
 
242
285
  # fill gaps with unknown-runtime if given, average otherwise
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ParallelTests
3
- VERSION = '3.7.3'
3
+ VERSION = '4.7.2'
4
4
  end
@@ -44,6 +44,8 @@ module ParallelTests
44
44
 
45
45
  def stop_all_processes
46
46
  pids.all.each { |pid| Process.kill(:INT, pid) }
47
+ rescue Errno::ESRCH, Errno::EPERM
48
+ # Process already terminated, do nothing
47
49
  end
48
50
 
49
51
  # copied from http://github.com/carlhuda/bundler Bundler::SharedHelpers#find_gemfile
@@ -76,7 +78,7 @@ module ParallelTests
76
78
  end
77
79
 
78
80
  def with_ruby_binary(command)
79
- WINDOWS ? "#{RUBY_BINARY} -- #{command}" : command
81
+ WINDOWS ? [RUBY_BINARY, '--', command] : [command]
80
82
  end
81
83
 
82
84
  def wait_for_other_processes_to_finish
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: 3.7.3
4
+ version: 4.7.2
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: 2021-09-17 00:00:00.000000000 Z
11
+ date: 2024-09-10 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
@@ -58,6 +58,7 @@ files:
58
58
  - lib/parallel_tests/rspec/runner.rb
59
59
  - lib/parallel_tests/rspec/runtime_logger.rb
60
60
  - lib/parallel_tests/rspec/summary_logger.rb
61
+ - lib/parallel_tests/rspec/verbose_logger.rb
61
62
  - lib/parallel_tests/spinach/runner.rb
62
63
  - lib/parallel_tests/tasks.rb
63
64
  - lib/parallel_tests/test/runner.rb
@@ -68,10 +69,11 @@ licenses:
68
69
  - MIT
69
70
  metadata:
70
71
  bug_tracker_uri: https://github.com/grosser/parallel_tests/issues
71
- documentation_uri: https://github.com/grosser/parallel_tests/blob/v3.7.3/Readme.md
72
- source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.7.3
72
+ changelog_uri: https://github.com/grosser/parallel_tests/blob/v4.7.2/CHANGELOG.md
73
+ documentation_uri: https://github.com/grosser/parallel_tests/blob/v4.7.2/Readme.md
74
+ source_code_uri: https://github.com/grosser/parallel_tests/tree/v4.7.2
73
75
  wiki_uri: https://github.com/grosser/parallel_tests/wiki
74
- post_install_message:
76
+ post_install_message:
75
77
  rdoc_options: []
76
78
  require_paths:
77
79
  - lib
@@ -79,15 +81,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
81
  requirements:
80
82
  - - ">="
81
83
  - !ruby/object:Gem::Version
82
- version: 2.5.0
84
+ version: 3.0.0
83
85
  required_rubygems_version: !ruby/object:Gem::Requirement
84
86
  requirements:
85
87
  - - ">="
86
88
  - !ruby/object:Gem::Version
87
89
  version: '0'
88
90
  requirements: []
89
- rubygems_version: 3.2.16
90
- signing_key:
91
+ rubygems_version: 3.4.10
92
+ signing_key:
91
93
  specification_version: 4
92
94
  summary: Run Test::Unit / RSpec / Cucumber / Spinach in parallel
93
95
  test_files: []