parallel_tests 3.7.3 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +5 -5
- data/lib/parallel_tests/cli.rb +8 -9
- data/lib/parallel_tests/cucumber/runner.rb +2 -2
- data/lib/parallel_tests/cucumber/scenarios.rb +1 -2
- data/lib/parallel_tests/gherkin/runner.rb +10 -15
- data/lib/parallel_tests/pids.rb +2 -2
- data/lib/parallel_tests/rspec/runner.rb +7 -14
- data/lib/parallel_tests/tasks.rb +88 -41
- data/lib/parallel_tests/test/runner.rb +40 -10
- data/lib/parallel_tests/version.rb +1 -1
- data/lib/parallel_tests.rb +1 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0685422bb8d62d97b1f15ae3276d80c4be5ffc75853aec063af5448033a1e03
|
4
|
+
data.tar.gz: 33f10bb91e35adc2806517b13da429f70cbb3e59e4476b4951117deddd60070c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8bb065572d8eff656a3b7e1ed0b2d2c4789acec9756943dc52d79d32964fc102c614c04d953b2385208839c8fd2befae7d3f8224fdab8cdcce1fb08f71b3990f
|
7
|
+
data.tar.gz: 222764ab45f7785af924b37ebd4f645f33c5274219b5a728504023dab9844b4e99b4a451cee7ea6f6df0e3c8c6790d7accde3ed604905ecf9dfbad3c905244c3
|
data/Readme.md
CHANGED
@@ -42,7 +42,7 @@ test:
|
|
42
42
|
|
43
43
|
### Setup environment from scratch (create db and loads schema, useful for CI)
|
44
44
|
rake parallel:setup
|
45
|
-
|
45
|
+
|
46
46
|
### Drop all test databases
|
47
47
|
rake parallel:drop
|
48
48
|
|
@@ -193,15 +193,15 @@ Setup for non-rails
|
|
193
193
|
- use `ENV['TEST_ENV_NUMBER']` inside your tests to select separate db/memcache/etc. (docker compose: expose it)
|
194
194
|
|
195
195
|
- Only run a subset of files / folders:
|
196
|
-
|
196
|
+
|
197
197
|
`parallel_test test/bar test/baz/foo_text.rb`
|
198
198
|
|
199
199
|
- Pass test-options and files via `--`:
|
200
|
-
|
200
|
+
|
201
201
|
`parallel_rspec -- -t acceptance -f progress -- spec/foo_spec.rb spec/acceptance`
|
202
|
-
|
202
|
+
|
203
203
|
- Pass in test options, by using the -o flag (wrap everything in quotes):
|
204
|
-
|
204
|
+
|
205
205
|
`parallel_cucumber -n 2 -o '-p foo_profile --tags @only_this_tag or @only_that_tag --format summary'`
|
206
206
|
|
207
207
|
Options are:
|
data/lib/parallel_tests/cli.rb
CHANGED
@@ -20,7 +20,7 @@ module ParallelTests
|
|
20
20
|
options[:first_is_1] ||= first_is_1?
|
21
21
|
|
22
22
|
if options[:execute]
|
23
|
-
|
23
|
+
execute_command_in_parallel(options[:execute], num_processes, options)
|
24
24
|
else
|
25
25
|
run_tests_in_parallel(num_processes, options)
|
26
26
|
end
|
@@ -100,7 +100,7 @@ module ParallelTests
|
|
100
100
|
|
101
101
|
def run_tests(group, process_number, num_processes, options)
|
102
102
|
if group.empty?
|
103
|
-
{ stdout: '', exit_status: 0, command:
|
103
|
+
{ stdout: '', exit_status: 0, command: nil, seed: nil }
|
104
104
|
else
|
105
105
|
@runner.run_tests(group, process_number, num_processes, options)
|
106
106
|
end
|
@@ -140,9 +140,8 @@ module ParallelTests
|
|
140
140
|
puts "\n\nTests have failed for a parallel_test group. Use the following command to run the group again:\n\n"
|
141
141
|
failing_sets.each do |failing_set|
|
142
142
|
command = failing_set[:command]
|
143
|
-
command = command.gsub(/;export [A-Z_]+;/, ' ') # remove ugly export statements
|
144
143
|
command = @runner.command_with_seed(command, failing_set[:seed]) if failing_set[:seed]
|
145
|
-
puts command
|
144
|
+
puts Shellwords.shelljoin(command)
|
146
145
|
end
|
147
146
|
end
|
148
147
|
end
|
@@ -238,8 +237,8 @@ module ParallelTests
|
|
238
237
|
|
239
238
|
opts.on("--only-group INT[,INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
|
240
239
|
|
241
|
-
opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |
|
242
|
-
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg
|
240
|
+
opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |arg| options[:execute] = Shellwords.shellsplit(arg) }
|
241
|
+
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = Shellwords.shellsplit(arg) }
|
243
242
|
opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
|
244
243
|
@runner = load_runner(type)
|
245
244
|
rescue NameError, LoadError => e
|
@@ -334,8 +333,8 @@ module ParallelTests
|
|
334
333
|
new_opts = extract_test_options(argv)
|
335
334
|
return if new_opts.empty?
|
336
335
|
|
337
|
-
|
338
|
-
options[:test_options]
|
336
|
+
options[:test_options] ||= []
|
337
|
+
options[:test_options] += new_opts
|
339
338
|
end
|
340
339
|
|
341
340
|
def load_runner(type)
|
@@ -345,7 +344,7 @@ module ParallelTests
|
|
345
344
|
klass_name.split('::').inject(Object) { |x, y| x.const_get(y) }
|
346
345
|
end
|
347
346
|
|
348
|
-
def
|
347
|
+
def execute_command_in_parallel(command, num_processes, options)
|
349
348
|
runs = if options[:only_group]
|
350
349
|
options[:only_group].map { |g| g - 1 }
|
351
350
|
else
|
@@ -35,8 +35,8 @@ module ParallelTests
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def command_with_seed(cmd, seed)
|
38
|
-
clean = cmd
|
39
|
-
|
38
|
+
clean = remove_command_arguments(cmd, '--order')
|
39
|
+
[*clean, '--order', "random:#{seed}"]
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -4,7 +4,6 @@ require 'cucumber/runtime'
|
|
4
4
|
require 'cucumber'
|
5
5
|
require 'parallel_tests/cucumber/scenario_line_logger'
|
6
6
|
require 'parallel_tests/gherkin/listener'
|
7
|
-
require 'shellwords'
|
8
7
|
|
9
8
|
begin
|
10
9
|
gem "cuke_modeler", "~> 3.0"
|
@@ -20,7 +19,7 @@ module ParallelTests
|
|
20
19
|
def all(files, options = {})
|
21
20
|
# Parse tag expression from given test options and ignore tag pattern. Refer here to understand how new tag expression syntax works - https://github.com/cucumber/cucumber/tree/master/tag-expressions
|
22
21
|
tags = []
|
23
|
-
words = options[:test_options]
|
22
|
+
words = options[:test_options] || []
|
24
23
|
words.each_with_index { |w, i| tags << words[i + 1] if ["-t", "--tags"].include?(w) }
|
25
24
|
if ignore = options[:ignore_tag_pattern]
|
26
25
|
tags << "not (#{ignore})"
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "parallel_tests/test/runner"
|
3
|
-
require 'shellwords'
|
4
3
|
|
5
4
|
module ParallelTests
|
6
5
|
module Gherkin
|
@@ -16,17 +15,13 @@ module ParallelTests
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
sanitized_test_files = combined_scenarios.map { |val| WINDOWS ? "\"#{val}\"" : Shellwords.escape(val) }
|
20
|
-
|
21
18
|
options[:env] ||= {}
|
22
19
|
options[:env] = options[:env].merge({ 'AUTOTEST' => '1' }) if $stdout.tty?
|
23
20
|
|
24
|
-
cmd =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
cucumber_opts(options[:test_options])
|
29
|
-
].compact.reject(&:empty?).join(' ')
|
21
|
+
cmd = executable
|
22
|
+
cmd += runtime_logging if File.directory?(File.dirname(runtime_log))
|
23
|
+
cmd += combined_scenarios
|
24
|
+
cmd += cucumber_opts(options[:test_options])
|
30
25
|
execute_command(cmd, process_number, num_processes, options)
|
31
26
|
end
|
32
27
|
|
@@ -67,17 +62,17 @@ module ParallelTests
|
|
67
62
|
end
|
68
63
|
|
69
64
|
def cucumber_opts(given)
|
70
|
-
if given
|
65
|
+
if given&.include?('--profile') || given&.include?('-p')
|
71
66
|
given
|
72
67
|
else
|
73
|
-
[given, profile_from_config]
|
68
|
+
[*given, *profile_from_config]
|
74
69
|
end
|
75
70
|
end
|
76
71
|
|
77
72
|
def profile_from_config
|
78
73
|
# copied from https://github.com/cucumber/cucumber/blob/master/lib/cucumber/cli/profile_loader.rb#L85
|
79
74
|
config = Dir.glob("{,.config/,config/}#{name}{.yml,.yaml}").first
|
80
|
-
|
75
|
+
['--profile', 'parallel'] if config && File.read(config) =~ /^parallel:/
|
81
76
|
end
|
82
77
|
|
83
78
|
def tests_in_groups(tests, num_groups, options = {})
|
@@ -91,7 +86,7 @@ module ParallelTests
|
|
91
86
|
end
|
92
87
|
|
93
88
|
def runtime_logging
|
94
|
-
|
89
|
+
['--format', 'ParallelTests::Gherkin::RuntimeLogger', '--out', runtime_log]
|
95
90
|
end
|
96
91
|
|
97
92
|
def runtime_log
|
@@ -102,11 +97,11 @@ module ParallelTests
|
|
102
97
|
if File.exist?("bin/#{name}")
|
103
98
|
ParallelTests.with_ruby_binary("bin/#{name}")
|
104
99
|
elsif ParallelTests.bundler_enabled?
|
105
|
-
"bundle exec
|
100
|
+
["bundle", "exec", name]
|
106
101
|
elsif File.file?("script/#{name}")
|
107
102
|
ParallelTests.with_ruby_binary("script/#{name}")
|
108
103
|
else
|
109
|
-
name.to_s
|
104
|
+
[name.to_s]
|
110
105
|
end
|
111
106
|
end
|
112
107
|
end
|
data/lib/parallel_tests/pids.rb
CHANGED
@@ -43,14 +43,14 @@ module ParallelTests
|
|
43
43
|
|
44
44
|
def read
|
45
45
|
sync do
|
46
|
-
contents =
|
46
|
+
contents = File.read(file_path)
|
47
47
|
return if contents.empty?
|
48
48
|
@pids = JSON.parse(contents)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
def save
|
53
|
-
sync {
|
53
|
+
sync { File.write(file_path, pids.to_json) }
|
54
54
|
end
|
55
55
|
|
56
56
|
def sync(&block)
|
@@ -7,8 +7,7 @@ module ParallelTests
|
|
7
7
|
DEV_NULL = (WINDOWS ? "NUL" : "/dev/null")
|
8
8
|
class << self
|
9
9
|
def run_tests(test_files, process_number, num_processes, options)
|
10
|
-
|
11
|
-
cmd = [exe, options[:test_options], color, spec_opts, *test_files].compact.join(" ")
|
10
|
+
cmd = [*executable, *options[:test_options], *color, *spec_opts, *test_files]
|
12
11
|
execute_command(cmd, process_number, num_processes, options)
|
13
12
|
end
|
14
13
|
|
@@ -16,9 +15,9 @@ module ParallelTests
|
|
16
15
|
if File.exist?("bin/rspec")
|
17
16
|
ParallelTests.with_ruby_binary("bin/rspec")
|
18
17
|
elsif ParallelTests.bundler_enabled?
|
19
|
-
"bundle exec rspec"
|
18
|
+
["bundle", "exec", "rspec"]
|
20
19
|
else
|
21
|
-
"rspec"
|
20
|
+
["rspec"]
|
22
21
|
end
|
23
22
|
end
|
24
23
|
|
@@ -48,8 +47,8 @@ module ParallelTests
|
|
48
47
|
# --order rand:1234
|
49
48
|
# --order random:1234
|
50
49
|
def command_with_seed(cmd, seed)
|
51
|
-
clean = cmd
|
52
|
-
|
50
|
+
clean = remove_command_arguments(cmd, '--seed', '--order')
|
51
|
+
[*clean, '--seed', seed]
|
53
52
|
end
|
54
53
|
|
55
54
|
# Summarize results from threads and colorize results based on failure and pending counts.
|
@@ -71,19 +70,13 @@ module ParallelTests
|
|
71
70
|
|
72
71
|
private
|
73
72
|
|
74
|
-
# so it can be stubbed....
|
75
|
-
def run(cmd)
|
76
|
-
`#{cmd}`
|
77
|
-
end
|
78
|
-
|
79
73
|
def color
|
80
|
-
'--color --tty' if $stdout.tty?
|
74
|
+
['--color', '--tty'] if $stdout.tty?
|
81
75
|
end
|
82
76
|
|
83
77
|
def spec_opts
|
84
78
|
options_file = ['.rspec_parallel', 'spec/parallel_spec.opts', 'spec/spec.opts'].detect { |f| File.file?(f) }
|
85
|
-
|
86
|
-
"-O #{options_file}"
|
79
|
+
["-O", options_file] if options_file
|
87
80
|
end
|
88
81
|
end
|
89
82
|
end
|
data/lib/parallel_tests/tasks.rb
CHANGED
@@ -18,7 +18,7 @@ module ParallelTests
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def load_lib
|
21
|
-
$LOAD_PATH << File.expand_path(
|
21
|
+
$LOAD_PATH << File.expand_path('..', __dir__)
|
22
22
|
require "parallel_tests"
|
23
23
|
end
|
24
24
|
|
@@ -30,12 +30,15 @@ module ParallelTests
|
|
30
30
|
|
31
31
|
def run_in_parallel(cmd, options = {})
|
32
32
|
load_lib
|
33
|
-
|
33
|
+
|
34
34
|
# Using the relative path to find the binary allow to run a specific version of it
|
35
35
|
executable = File.expand_path('../../bin/parallel_test', __dir__)
|
36
|
-
|
37
|
-
command
|
38
|
-
|
36
|
+
command = ParallelTests.with_ruby_binary(executable)
|
37
|
+
command += ['--exec', Shellwords.join(cmd)]
|
38
|
+
command += ['-n', options[:count]] unless options[:count].to_s.empty?
|
39
|
+
command << '--non-parallel' if options[:non_parallel]
|
40
|
+
|
41
|
+
abort unless system(*command)
|
39
42
|
end
|
40
43
|
|
41
44
|
# this is a crazy-complex solution for a very simple problem:
|
@@ -48,16 +51,14 @@ module ParallelTests
|
|
48
51
|
# - pipefail makes pipe fail with exitstatus of first failed command
|
49
52
|
# - pipefail is not supported in (zsh)
|
50
53
|
# - defining a new rake task like silence_schema would force users to load parallel_tests in test env
|
51
|
-
# - do not use ' since run_in_parallel uses them to quote stuff
|
52
54
|
# - simple system "set -o pipefail" returns nil even though set -o pipefail exists with 0
|
53
55
|
def suppress_output(command, ignore_regex)
|
54
56
|
activate_pipefail = "set -o pipefail"
|
55
|
-
remove_ignored_lines = %{(grep -v
|
57
|
+
remove_ignored_lines = %{(grep -v #{Shellwords.escape(ignore_regex)} || true)}
|
56
58
|
|
57
|
-
if
|
58
|
-
|
59
|
-
|
60
|
-
%{/bin/bash -c '"'"'#{activate_pipefail} && (#{command}) | #{remove_ignored_lines}'"'"'}
|
59
|
+
if system('/bin/bash', '-c', "#{activate_pipefail} 2>/dev/null")
|
60
|
+
shell_command = "#{activate_pipefail} && (#{Shellwords.shelljoin(command)}) | #{remove_ignored_lines}"
|
61
|
+
['/bin/bash', '-c', shell_command]
|
61
62
|
else
|
62
63
|
command
|
63
64
|
end
|
@@ -90,7 +91,33 @@ module ParallelTests
|
|
90
91
|
options = args.shift
|
91
92
|
pass_through = args.shift
|
92
93
|
|
93
|
-
[num_processes, pattern
|
94
|
+
[num_processes, pattern, options, pass_through]
|
95
|
+
end
|
96
|
+
|
97
|
+
def schema_format_based_on_rails_version
|
98
|
+
if rails_7_or_greater?
|
99
|
+
ActiveRecord.schema_format
|
100
|
+
else
|
101
|
+
ActiveRecord::Base.schema_format
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def schema_type_based_on_rails_version
|
106
|
+
if rails_61_or_greater? || schema_format_based_on_rails_version == :ruby
|
107
|
+
"schema"
|
108
|
+
else
|
109
|
+
"structure"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def rails_7_or_greater?
|
116
|
+
Gem::Version.new(Rails.version) >= Gem::Version.new('7.0')
|
117
|
+
end
|
118
|
+
|
119
|
+
def rails_61_or_greater?
|
120
|
+
Gem::Version.new(Rails.version) >= Gem::Version.new('6.1.0')
|
94
121
|
end
|
95
122
|
end
|
96
123
|
end
|
@@ -106,29 +133,31 @@ namespace :parallel do
|
|
106
133
|
desc "Create test databases via db:create --> parallel:create[num_cpus]"
|
107
134
|
task :create, :count do |_, args|
|
108
135
|
ParallelTests::Tasks.run_in_parallel(
|
109
|
-
|
136
|
+
[ParallelTests::Tasks.rake_bin, "db:create", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
137
|
+
args
|
110
138
|
)
|
111
139
|
end
|
112
140
|
|
113
141
|
desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
|
114
142
|
task :drop, :count do |_, args|
|
115
143
|
ParallelTests::Tasks.run_in_parallel(
|
116
|
-
|
117
|
-
|
144
|
+
[
|
145
|
+
ParallelTests::Tasks.rake_bin,
|
146
|
+
"db:drop",
|
147
|
+
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
|
148
|
+
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
149
|
+
],
|
150
|
+
args
|
118
151
|
)
|
119
152
|
end
|
120
153
|
|
121
154
|
desc "Update test databases by dumping and loading --> parallel:prepare[num_cpus]"
|
122
155
|
task(:prepare, [:count]) do |_, args|
|
123
156
|
ParallelTests::Tasks.check_for_pending_migrations
|
124
|
-
|
157
|
+
|
158
|
+
if defined?(ActiveRecord) && [:ruby, :sql].include?(ParallelTests::Tasks.schema_format_based_on_rails_version)
|
125
159
|
# fast: dump once, load in parallel
|
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
|
160
|
+
type = ParallelTests::Tasks.schema_type_based_on_rails_version
|
132
161
|
|
133
162
|
Rake::Task["db:#{type}:dump"].invoke
|
134
163
|
|
@@ -140,7 +169,7 @@ namespace :parallel do
|
|
140
169
|
# slow: dump and load in in serial
|
141
170
|
args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
|
142
171
|
task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
|
143
|
-
ParallelTests::Tasks.run_in_parallel(
|
172
|
+
ParallelTests::Tasks.run_in_parallel([ParallelTests::Tasks.rake_bin, task_name], args)
|
144
173
|
next
|
145
174
|
end
|
146
175
|
end
|
@@ -149,22 +178,29 @@ namespace :parallel do
|
|
149
178
|
desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
|
150
179
|
task :migrate, :count do |_, args|
|
151
180
|
ParallelTests::Tasks.run_in_parallel(
|
152
|
-
|
181
|
+
[ParallelTests::Tasks.rake_bin, "db:migrate", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
182
|
+
args
|
153
183
|
)
|
154
184
|
end
|
155
185
|
|
156
186
|
desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
|
157
187
|
task :rollback, :count do |_, args|
|
158
188
|
ParallelTests::Tasks.run_in_parallel(
|
159
|
-
|
189
|
+
[ParallelTests::Tasks.rake_bin, "db:rollback", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
190
|
+
args
|
160
191
|
)
|
161
192
|
end
|
162
193
|
|
163
194
|
# just load the schema (good for integration server <-> no development db)
|
164
195
|
desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
|
165
196
|
task :load_schema, :count do |_, args|
|
166
|
-
command =
|
167
|
-
|
197
|
+
command = [
|
198
|
+
ParallelTests::Tasks.rake_bin,
|
199
|
+
ParallelTests::Tasks.purge_before_load,
|
200
|
+
"db:schema:load",
|
201
|
+
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
|
202
|
+
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
203
|
+
]
|
168
204
|
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
|
169
205
|
end
|
170
206
|
|
@@ -173,23 +209,34 @@ namespace :parallel do
|
|
173
209
|
desc "Load structure for test databases via db:schema:load --> parallel:load_structure[num_cpus]"
|
174
210
|
task :load_structure, :count do |_, args|
|
175
211
|
ParallelTests::Tasks.run_in_parallel(
|
176
|
-
|
177
|
-
|
212
|
+
[
|
213
|
+
ParallelTests::Tasks.rake_bin,
|
214
|
+
ParallelTests::Tasks.purge_before_load,
|
215
|
+
"db:structure:load",
|
216
|
+
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}",
|
217
|
+
"DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
|
218
|
+
],
|
219
|
+
args
|
178
220
|
)
|
179
221
|
end
|
180
222
|
|
181
223
|
desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
|
182
224
|
task :seed, :count do |_, args|
|
183
225
|
ParallelTests::Tasks.run_in_parallel(
|
184
|
-
|
226
|
+
[
|
227
|
+
ParallelTests::Tasks.rake_bin,
|
228
|
+
"db:seed",
|
229
|
+
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
|
230
|
+
],
|
231
|
+
args
|
185
232
|
)
|
186
233
|
end
|
187
234
|
|
188
235
|
desc "Launch given rake command in parallel"
|
189
236
|
task :rake, :command, :count do |_, args|
|
190
237
|
ParallelTests::Tasks.run_in_parallel(
|
191
|
-
|
192
|
-
|
238
|
+
[ParallelTests::Tasks.rake_bin, args.command, "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
239
|
+
args
|
193
240
|
)
|
194
241
|
end
|
195
242
|
|
@@ -209,15 +256,15 @@ namespace :parallel do
|
|
209
256
|
|
210
257
|
type = 'features' if test_framework == 'spinach'
|
211
258
|
# Using the relative path to find the binary allow to run a specific version of it
|
212
|
-
executable = File.
|
213
|
-
|
214
|
-
command =
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
abort unless system(command) # allow to chain tasks e.g. rake parallel:spec parallel:features
|
259
|
+
executable = File.expand_path('../../bin/parallel_test', __dir__)
|
260
|
+
|
261
|
+
command = [*ParallelTests.with_ruby_binary(executable), type, '--type', test_framework]
|
262
|
+
command += ['-n', count] if count
|
263
|
+
command += ['--pattern', pattern] if pattern
|
264
|
+
command += ['--test-options', options] if options
|
265
|
+
command << pass_through if pass_through
|
266
|
+
|
267
|
+
abort unless system(*command) # allow to chain tasks e.g. rake parallel:spec parallel:features
|
221
268
|
end
|
222
269
|
end
|
223
270
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'shellwords'
|
2
3
|
require 'parallel_tests'
|
3
4
|
|
4
5
|
module ParallelTests
|
@@ -25,7 +26,14 @@ module ParallelTests
|
|
25
26
|
|
26
27
|
def run_tests(test_files, process_number, num_processes, options)
|
27
28
|
require_list = test_files.map { |file| file.gsub(" ", "\\ ") }.join(" ")
|
28
|
-
cmd =
|
29
|
+
cmd = [
|
30
|
+
*executable,
|
31
|
+
'-Itest',
|
32
|
+
'-e',
|
33
|
+
"%w[#{require_list}].each { |f| require %{./\#{f}} }",
|
34
|
+
'--',
|
35
|
+
*options[:test_options]
|
36
|
+
]
|
29
37
|
execute_command(cmd, process_number, num_processes, options)
|
30
38
|
end
|
31
39
|
|
@@ -81,17 +89,20 @@ module ParallelTests
|
|
81
89
|
"PARALLEL_TEST_GROUPS" => num_processes.to_s,
|
82
90
|
"PARALLEL_PID_FILE" => ParallelTests.pid_file_path
|
83
91
|
)
|
84
|
-
cmd = "nice
|
85
|
-
cmd = "#{cmd} 2>&1" if options[:combine_stderr]
|
92
|
+
cmd = ["nice", *cmd] if options[:nice]
|
86
93
|
|
87
|
-
puts cmd if report_process_command?(options) && !options[:serialize_stdout]
|
94
|
+
puts Shellwords.shelljoin(cmd) if report_process_command?(options) && !options[:serialize_stdout]
|
88
95
|
|
89
96
|
execute_command_and_capture_output(env, cmd, options)
|
90
97
|
end
|
91
98
|
|
92
99
|
def execute_command_and_capture_output(env, cmd, options)
|
93
100
|
pid = nil
|
94
|
-
|
101
|
+
|
102
|
+
popen_options = {}
|
103
|
+
popen_options[:err] = [:child, :out] if options[:combine_stderr]
|
104
|
+
|
105
|
+
output = IO.popen(env, cmd, popen_options) do |io|
|
95
106
|
pid = io.pid
|
96
107
|
ParallelTests.pids.add(pid)
|
97
108
|
capture_output(io, env, options)
|
@@ -100,7 +111,7 @@ module ParallelTests
|
|
100
111
|
exitstatus = $?.exitstatus
|
101
112
|
seed = output[/seed (\d+)/, 1]
|
102
113
|
|
103
|
-
output =
|
114
|
+
output = "#{Shellwords.shelljoin(cmd)}\n#{output}" if report_process_command?(options) && options[:serialize_stdout]
|
104
115
|
|
105
116
|
{ stdout: output, exit_status: exitstatus, command: cmd, seed: seed }
|
106
117
|
end
|
@@ -129,18 +140,22 @@ module ParallelTests
|
|
129
140
|
|
130
141
|
# remove old seed and add new seed
|
131
142
|
def command_with_seed(cmd, seed)
|
132
|
-
clean = cmd
|
133
|
-
|
143
|
+
clean = remove_command_arguments(cmd, '--seed')
|
144
|
+
[*clean, '--seed', seed]
|
134
145
|
end
|
135
146
|
|
136
147
|
protected
|
137
148
|
|
138
149
|
def executable
|
139
|
-
ENV
|
150
|
+
if ENV.include?('PARALLEL_TESTS_EXECUTABLE')
|
151
|
+
[ENV['PARALLEL_TESTS_EXECUTABLE']]
|
152
|
+
else
|
153
|
+
determine_executable
|
154
|
+
end
|
140
155
|
end
|
141
156
|
|
142
157
|
def determine_executable
|
143
|
-
"ruby"
|
158
|
+
["ruby"]
|
144
159
|
end
|
145
160
|
|
146
161
|
def sum_up_results(results)
|
@@ -237,6 +252,21 @@ module ParallelTests
|
|
237
252
|
Dir[File.join(folder, pattern)].uniq.sort
|
238
253
|
end
|
239
254
|
|
255
|
+
def remove_command_arguments(command, *args)
|
256
|
+
remove_next = false
|
257
|
+
command.select do |arg|
|
258
|
+
if remove_next
|
259
|
+
remove_next = false
|
260
|
+
false
|
261
|
+
elsif args.include?(arg)
|
262
|
+
remove_next = true
|
263
|
+
false
|
264
|
+
else
|
265
|
+
true
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
240
270
|
private
|
241
271
|
|
242
272
|
# fill gaps with unknown-runtime if given, average otherwise
|
data/lib/parallel_tests.rb
CHANGED
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.
|
4
|
+
version: 3.9.0
|
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:
|
11
|
+
date: 2022-05-22 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
|
@@ -68,10 +68,10 @@ licenses:
|
|
68
68
|
- MIT
|
69
69
|
metadata:
|
70
70
|
bug_tracker_uri: https://github.com/grosser/parallel_tests/issues
|
71
|
-
documentation_uri: https://github.com/grosser/parallel_tests/blob/v3.
|
72
|
-
source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.
|
71
|
+
documentation_uri: https://github.com/grosser/parallel_tests/blob/v3.9.0/Readme.md
|
72
|
+
source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.9.0
|
73
73
|
wiki_uri: https://github.com/grosser/parallel_tests/wiki
|
74
|
-
post_install_message:
|
74
|
+
post_install_message:
|
75
75
|
rdoc_options: []
|
76
76
|
require_paths:
|
77
77
|
- lib
|
@@ -86,8 +86,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
86
|
- !ruby/object:Gem::Version
|
87
87
|
version: '0'
|
88
88
|
requirements: []
|
89
|
-
rubygems_version: 3.
|
90
|
-
signing_key:
|
89
|
+
rubygems_version: 3.3.3
|
90
|
+
signing_key:
|
91
91
|
specification_version: 4
|
92
92
|
summary: Run Test::Unit / RSpec / Cucumber / Spinach in parallel
|
93
93
|
test_files: []
|