parallel_tests 3.7.3 → 3.9.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.
- 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: []
|