parallel_tests 3.8.0 → 3.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +6 -5
- data/lib/parallel_tests/cli.rb +10 -11
- data/lib/parallel_tests/cucumber/runner.rb +2 -2
- data/lib/parallel_tests/cucumber/scenario_line_logger.rb +1 -1
- data/lib/parallel_tests/cucumber/scenarios.rb +1 -2
- data/lib/parallel_tests/gherkin/runner.rb +11 -16
- data/lib/parallel_tests/grouper.rb +1 -1
- data/lib/parallel_tests/rspec/runner.rb +7 -14
- data/lib/parallel_tests/tasks.rb +60 -37
- 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 +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f47ccd447d00db0be7c9f7ae419b3d2083f0529624859546a6a1dee52337604f
|
4
|
+
data.tar.gz: 624a59d50ba0d167ab2bbbf5ee946fa3917ba57fb3cc256f3c2e5b4855349343
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac848edaee8de2a79d5cae89ddfe59df61b37d1464048f5d591d488a26db044f0fd97e2669fe6b69772ad3e449bc1cb28faa0c627d0114d57cd657a222ec39e0
|
7
|
+
data.tar.gz: 77f69505ddcbec907cdd45d955d7512b96509e003757bbc42f0ad188ee4083945f33316cf8d5a423b3dfe0e4181038e70e3cb68b8be152649cb3631d564dcb11
|
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:
|
@@ -402,6 +402,7 @@ inspired by [pivotal labs](https://blog.pivotal.io/labs/labs/parallelize-your-rs
|
|
402
402
|
- [Vikram B Kumar](https://github.com/v-kumar)
|
403
403
|
- [Joshua Pinter](https://github.com/joshuapinter)
|
404
404
|
- [Zach Dennis](https://github.com/zdennis)
|
405
|
+
- [Jon Dufresne](https://github.com/jdufresne)
|
405
406
|
|
406
407
|
[Michael Grosser](http://grosser.it)<br/>
|
407
408
|
michael@grosser.it<br/>
|
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
|
@@ -322,20 +321,20 @@ module ParallelTests
|
|
322
321
|
def extract_file_paths(argv)
|
323
322
|
dash_index = argv.rindex("--")
|
324
323
|
file_args_at = (dash_index || -1) + 1
|
325
|
-
[argv[file_args_at
|
324
|
+
[argv[file_args_at..-1], argv[0...(dash_index || 0)]]
|
326
325
|
end
|
327
326
|
|
328
327
|
def extract_test_options(argv)
|
329
328
|
dash_index = argv.index("--") || -1
|
330
|
-
argv[dash_index + 1
|
329
|
+
argv[dash_index + 1..-1]
|
331
330
|
end
|
332
331
|
|
333
332
|
def append_test_options(options, argv)
|
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
|
@@ -27,7 +27,7 @@ module ParallelTests
|
|
27
27
|
example_tags = example.tags.map(&:name)
|
28
28
|
example_tags = scenario_tags + example_tags
|
29
29
|
next unless matches_tags?(example_tags)
|
30
|
-
example.rows[1
|
30
|
+
example.rows[1..-1].each do |row|
|
31
31
|
test_line = row.source_line
|
32
32
|
next if line_numbers.any? && !line_numbers.include?(test_line)
|
33
33
|
|
@@ -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
|
|
@@ -62,22 +57,22 @@ module ParallelTests
|
|
62
57
|
plural = "s" if (word == group) && (number != 1)
|
63
58
|
"#{number} #{word}#{plural}"
|
64
59
|
end
|
65
|
-
"#{sums[0]} (#{sums[1
|
60
|
+
"#{sums[0]} (#{sums[1..-1].join(", ")})"
|
66
61
|
end.compact.join("\n")
|
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
|
@@ -38,7 +38,7 @@ module ParallelTests
|
|
38
38
|
# add all files that should run in a multiple isolated processes to their own groups
|
39
39
|
group_features_by_size(items_to_group(single_items), groups[0..(isolate_count - 1)])
|
40
40
|
# group the non-isolated by size
|
41
|
-
group_features_by_size(items_to_group(items), groups[isolate_count
|
41
|
+
group_features_by_size(items_to_group(items), groups[isolate_count..-1])
|
42
42
|
else
|
43
43
|
# add all files that should run in a single non-isolated process to first group
|
44
44
|
single_items.each { |item, size| add_to_group(groups.first, item, size) }
|
@@ -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,7 @@ 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]
|
94
95
|
end
|
95
96
|
|
96
97
|
def schema_format_based_on_rails_version
|
@@ -125,22 +126,28 @@ end
|
|
125
126
|
namespace :parallel do
|
126
127
|
desc "Setup test databases via db:setup --> parallel:setup[num_cpus]"
|
127
128
|
task :setup, :count do |_, args|
|
128
|
-
command =
|
129
|
+
command = [ParallelTests::Tasks.rake_bin, "db:setup", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"]
|
129
130
|
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
|
130
131
|
end
|
131
132
|
|
132
133
|
desc "Create test databases via db:create --> parallel:create[num_cpus]"
|
133
134
|
task :create, :count do |_, args|
|
134
135
|
ParallelTests::Tasks.run_in_parallel(
|
135
|
-
|
136
|
+
[ParallelTests::Tasks.rake_bin, "db:create", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
137
|
+
args
|
136
138
|
)
|
137
139
|
end
|
138
140
|
|
139
141
|
desc "Drop test databases via db:drop --> parallel:drop[num_cpus]"
|
140
142
|
task :drop, :count do |_, args|
|
141
143
|
ParallelTests::Tasks.run_in_parallel(
|
142
|
-
|
143
|
-
|
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
|
144
151
|
)
|
145
152
|
end
|
146
153
|
|
@@ -162,7 +169,7 @@ namespace :parallel do
|
|
162
169
|
# slow: dump and load in in serial
|
163
170
|
args = args.to_hash.merge(non_parallel: true) # normal merge returns nil
|
164
171
|
task_name = Rake::Task.task_defined?('db:test:prepare') ? 'db:test:prepare' : 'app:db:test:prepare'
|
165
|
-
ParallelTests::Tasks.run_in_parallel(
|
172
|
+
ParallelTests::Tasks.run_in_parallel([ParallelTests::Tasks.rake_bin, task_name], args)
|
166
173
|
next
|
167
174
|
end
|
168
175
|
end
|
@@ -171,23 +178,29 @@ namespace :parallel do
|
|
171
178
|
desc "Update test databases via db:migrate --> parallel:migrate[num_cpus]"
|
172
179
|
task :migrate, :count do |_, args|
|
173
180
|
ParallelTests::Tasks.run_in_parallel(
|
174
|
-
|
181
|
+
[ParallelTests::Tasks.rake_bin, "db:migrate", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
182
|
+
args
|
175
183
|
)
|
176
184
|
end
|
177
185
|
|
178
186
|
desc "Rollback test databases via db:rollback --> parallel:rollback[num_cpus]"
|
179
187
|
task :rollback, :count do |_, args|
|
180
188
|
ParallelTests::Tasks.run_in_parallel(
|
181
|
-
|
189
|
+
[ParallelTests::Tasks.rake_bin, "db:rollback", "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
190
|
+
args
|
182
191
|
)
|
183
192
|
end
|
184
193
|
|
185
194
|
# just load the schema (good for integration server <-> no development db)
|
186
195
|
desc "Load dumped schema for test databases via db:schema:load --> parallel:load_schema[num_cpus]"
|
187
196
|
task :load_schema, :count do |_, args|
|
188
|
-
command =
|
189
|
-
|
190
|
-
|
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
|
+
]
|
191
204
|
ParallelTests::Tasks.run_in_parallel(ParallelTests::Tasks.suppress_schema_load_output(command), args)
|
192
205
|
end
|
193
206
|
|
@@ -196,23 +209,34 @@ namespace :parallel do
|
|
196
209
|
desc "Load structure for test databases via db:schema:load --> parallel:load_structure[num_cpus]"
|
197
210
|
task :load_structure, :count do |_, args|
|
198
211
|
ParallelTests::Tasks.run_in_parallel(
|
199
|
-
|
200
|
-
|
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
|
201
220
|
)
|
202
221
|
end
|
203
222
|
|
204
223
|
desc "Load the seed data from db/seeds.rb via db:seed --> parallel:seed[num_cpus]"
|
205
224
|
task :seed, :count do |_, args|
|
206
225
|
ParallelTests::Tasks.run_in_parallel(
|
207
|
-
|
226
|
+
[
|
227
|
+
ParallelTests::Tasks.rake_bin,
|
228
|
+
"db:seed",
|
229
|
+
"RAILS_ENV=#{ParallelTests::Tasks.rails_env}"
|
230
|
+
],
|
231
|
+
args
|
208
232
|
)
|
209
233
|
end
|
210
234
|
|
211
235
|
desc "Launch given rake command in parallel"
|
212
236
|
task :rake, :command, :count do |_, args|
|
213
237
|
ParallelTests::Tasks.run_in_parallel(
|
214
|
-
|
215
|
-
|
238
|
+
[ParallelTests::Tasks.rake_bin, args.command, "RAILS_ENV=#{ParallelTests::Tasks.rails_env}"],
|
239
|
+
args
|
216
240
|
)
|
217
241
|
end
|
218
242
|
|
@@ -232,16 +256,15 @@ namespace :parallel do
|
|
232
256
|
|
233
257
|
type = 'features' if test_framework == 'spinach'
|
234
258
|
# Using the relative path to find the binary allow to run a specific version of it
|
235
|
-
executable = File.
|
236
|
-
|
237
|
-
command =
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
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
|
245
268
|
end
|
246
269
|
end
|
247
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.1
|
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: 2022-
|
11
|
+
date: 2022-05-23 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.1/Readme.md
|
72
|
+
source_code_uri: https://github.com/grosser/parallel_tests/tree/v3.9.1
|
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
|
@@ -79,15 +79,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 2.
|
82
|
+
version: 2.5.0
|
83
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
84
|
requirements:
|
85
85
|
- - ">="
|
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: []
|