parallel_tests 3.8.0 → 3.9.1
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 +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: []
|