parallel_tests 3.4.0 → 3.7.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 +32 -18
- data/bin/parallel_cucumber +2 -1
- data/bin/parallel_rspec +2 -1
- data/bin/parallel_spinach +2 -1
- data/bin/parallel_test +2 -1
- data/lib/parallel_tests.rb +12 -12
- data/lib/parallel_tests/cli.rb +120 -65
- data/lib/parallel_tests/cucumber/failures_logger.rb +1 -1
- data/lib/parallel_tests/cucumber/features_with_steps.rb +4 -3
- data/lib/parallel_tests/cucumber/runner.rb +8 -5
- data/lib/parallel_tests/cucumber/scenario_line_logger.rb +3 -3
- data/lib/parallel_tests/cucumber/scenarios.rb +5 -5
- data/lib/parallel_tests/gherkin/io.rb +2 -3
- data/lib/parallel_tests/gherkin/listener.rb +9 -10
- data/lib/parallel_tests/gherkin/runner.rb +20 -21
- data/lib/parallel_tests/gherkin/runtime_logger.rb +2 -1
- data/lib/parallel_tests/grouper.rb +56 -5
- data/lib/parallel_tests/pids.rb +3 -2
- data/lib/parallel_tests/railtie.rb +1 -0
- data/lib/parallel_tests/rspec/failures_logger.rb +2 -2
- data/lib/parallel_tests/rspec/logger_base.rb +9 -7
- data/lib/parallel_tests/rspec/runner.rb +11 -7
- data/lib/parallel_tests/rspec/runtime_logger.rb +12 -10
- data/lib/parallel_tests/rspec/summary_logger.rb +2 -3
- data/lib/parallel_tests/spinach/runner.rb +6 -2
- data/lib/parallel_tests/tasks.rb +44 -30
- data/lib/parallel_tests/test/runner.rb +36 -27
- data/lib/parallel_tests/test/runtime_logger.rb +19 -14
- data/lib/parallel_tests/version.rb +2 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 52c2ebdfc604b9e238867ea3d7d78cb919d60c951ab45bd2ead93db8893352f4
|
|
4
|
+
data.tar.gz: 441cf2b41a814746e1704fd794cd147638dbd261f1b294fd74b49adb9bc6d0da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a20853e2eac4f7b4260ea3ac3a9515b3d83fa3b47ff411a5f9567fcde257044825b2e9a81047e01f4d72722c02a6fdd2dbffba026dafb236cff8c2be2b712134
|
|
7
|
+
data.tar.gz: 4483fac06b11b0615b2bd39dcc5487713a02105cac547cf50177ec30805a8b17ebdbbac679e88a84f57da702235998cc0f67b80e382ea0bd27e784f4e89639a0
|
data/Readme.md
CHANGED
|
@@ -37,6 +37,9 @@ test:
|
|
|
37
37
|
### Copy development schema (repeat after migrations)
|
|
38
38
|
rake parallel:prepare
|
|
39
39
|
|
|
40
|
+
### Run migrations in additional database(s) (repeat after migrations)
|
|
41
|
+
rake parallel:migrate
|
|
42
|
+
|
|
40
43
|
### Setup environment from scratch (create db and loads schema, useful for CI)
|
|
41
44
|
rake parallel:setup
|
|
42
45
|
|
|
@@ -142,17 +145,19 @@ Add the following to your `.rspec_parallel` (or `.rspec`) :
|
|
|
142
145
|
RSpec: FailuresLogger
|
|
143
146
|
-----------------------
|
|
144
147
|
|
|
145
|
-
Produce
|
|
148
|
+
Produce pastable command-line snippets for each failed example. For example:
|
|
146
149
|
|
|
147
|
-
|
|
150
|
+
```bash
|
|
151
|
+
rspec /path/to/my_spec.rb:123 # should do something
|
|
152
|
+
```
|
|
148
153
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
Add the following to your `.rspec_parallel` (or `.rspec`) :
|
|
154
|
+
Add to `.rspec_parallel` or use as CLI flag:
|
|
152
155
|
|
|
153
156
|
--format progress
|
|
154
157
|
--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
|
|
155
158
|
|
|
159
|
+
(Not needed to retry failures, for that pass [--only-failures](https://relishapp.com/rspec/rspec-core/docs/command-line/only-failures) to rspec)
|
|
160
|
+
|
|
156
161
|
Cucumber: FailuresLogger
|
|
157
162
|
-----------------------
|
|
158
163
|
|
|
@@ -197,24 +202,32 @@ Options are:
|
|
|
197
202
|
-p, --pattern [PATTERN] run tests matching this regex pattern
|
|
198
203
|
--exclude-pattern [PATTERN] exclude tests matching this regex pattern
|
|
199
204
|
--group-by [TYPE] group tests by:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
found - order of finding files
|
|
206
|
+
steps - number of cucumber/spinach steps
|
|
207
|
+
scenarios - individual cucumber scenarios
|
|
208
|
+
filesize - by size of the file
|
|
209
|
+
runtime - info from runtime log
|
|
210
|
+
default - runtime when runtime log is filled otherwise filesize
|
|
206
211
|
-m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
|
|
207
212
|
-s, --single [PATTERN] Run all matching files in the same process
|
|
208
|
-
-i, --isolate Do not run any other tests in the group used by --single(-s)
|
|
209
|
-
|
|
210
|
-
--
|
|
211
|
-
--
|
|
213
|
+
-i, --isolate Do not run any other tests in the group used by --single(-s)
|
|
214
|
+
--isolate-n [PROCESSES] Use 'isolate' singles with number of processes, default: 1.
|
|
215
|
+
--highest-exit-status Exit with the highest exit status provided by test run(s)
|
|
216
|
+
--specify-groups [SPECS] Use 'specify-groups' if you want to specify multiple specs running in multiple
|
|
217
|
+
processes in a specific formation. Commas indicate specs in the same process,
|
|
218
|
+
pipes indicate specs in a new process. Cannot use with --single, --isolate, or
|
|
219
|
+
--isolate-n. Ex.
|
|
220
|
+
$ parallel_tests -n 3 . --specify-groups '1_spec.rb,2_spec.rb|3_spec.rb'
|
|
221
|
+
Process 1 will contain 1_spec.rb and 2_spec.rb
|
|
222
|
+
Process 2 will contain 3_spec.rb
|
|
223
|
+
Process 3 will contain all other specs
|
|
224
|
+
--only-group INT[,INT]
|
|
212
225
|
-e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUMBER']
|
|
213
226
|
-o, --test-options '[OPTIONS]' execute test commands with those options
|
|
214
227
|
-t, --type [TYPE] test(default) / rspec / cucumber / spinach
|
|
215
228
|
--suffix [PATTERN] override built in test file pattern (should match suffix):
|
|
216
|
-
|
|
217
|
-
|
|
229
|
+
'_spec.rb$' - matches rspec files
|
|
230
|
+
'_(test|spec).rb$' - matches test or spec files
|
|
218
231
|
--serialize-stdout Serialize stdout output, nothing will be written until everything is done
|
|
219
232
|
--prefix-output-with-test-env-number
|
|
220
233
|
Prefixes test env number to the output when not using --serialize-stdout
|
|
@@ -282,7 +295,7 @@ TIPS
|
|
|
282
295
|
`export PARALLEL_TEST_FIRST_IS_1=true` will provide the same result
|
|
283
296
|
- [email_spec and/or action_mailer_cache_delivery](https://github.com/grosser/parallel_tests/wiki)
|
|
284
297
|
- [zeus-parallel_tests](https://github.com/sevos/zeus-parallel_tests)
|
|
285
|
-
- [Distributed
|
|
298
|
+
- [Distributed Parallel Tests on CI systems)](https://github.com/grosser/parallel_tests/wiki/Distributed-Parallel-Tests-on-CI-systems) learn how `parallel_tests` can run on distributed servers such as Travis and GitLab-CI. Also shows you how to use parallel_tests without adding `TEST_ENV_NUMBER`-backends
|
|
286
299
|
- [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
|
|
287
300
|
- [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
|
|
288
301
|
- [Capistrano setup](https://github.com/grosser/parallel_tests/wiki/Remotely-with-capistrano) let your tests run on a big box instead of your laptop
|
|
@@ -379,6 +392,7 @@ inspired by [pivotal labs](https://blog.pivotal.io/labs/labs/parallelize-your-rs
|
|
|
379
392
|
- [alboyadjian](https://github.com/alboyadjian)
|
|
380
393
|
- [Nathan Broadbent](https://github.com/ndbroadbent)
|
|
381
394
|
- [Vikram B Kumar](https://github.com/v-kumar)
|
|
395
|
+
- [Joshua Pinter](https://github.com/joshuapinter)
|
|
382
396
|
|
|
383
397
|
[Michael Grosser](http://grosser.it)<br/>
|
|
384
398
|
michael@grosser.it<br/>
|
data/bin/parallel_cucumber
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
# enable local usage from cloned repo
|
|
4
|
-
root = File.expand_path(
|
|
5
|
+
root = File.expand_path('..', __dir__)
|
|
5
6
|
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
|
6
7
|
|
|
7
8
|
require "parallel_tests"
|
data/bin/parallel_rspec
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
# enable local usage from cloned repo
|
|
4
|
-
root = File.expand_path(
|
|
5
|
+
root = File.expand_path('..', __dir__)
|
|
5
6
|
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
|
6
7
|
|
|
7
8
|
require "parallel_tests"
|
data/bin/parallel_spinach
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
# enable local usage from cloned repo
|
|
4
|
-
root = File.expand_path(
|
|
5
|
+
root = File.expand_path('..', __dir__)
|
|
5
6
|
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
|
6
7
|
|
|
7
8
|
require "parallel_tests"
|
data/bin/parallel_test
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
# enable local usage from cloned repo
|
|
4
|
-
root = File.expand_path(
|
|
5
|
+
root = File.expand_path('..', __dir__)
|
|
5
6
|
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
|
6
7
|
|
|
7
8
|
require "parallel_tests"
|
data/lib/parallel_tests.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require "parallel"
|
|
2
3
|
require "parallel_tests/railtie" if defined? Rails::Railtie
|
|
3
4
|
require "rbconfig"
|
|
@@ -17,21 +18,19 @@ module ParallelTests
|
|
|
17
18
|
count,
|
|
18
19
|
ENV["PARALLEL_TEST_PROCESSORS"],
|
|
19
20
|
Parallel.processor_count
|
|
20
|
-
].detect{|c|
|
|
21
|
+
].detect { |c| !c.to_s.strip.empty? }.to_i
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def with_pid_file
|
|
24
25
|
Tempfile.open('parallel_tests-pidfile') do |f|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@pids = nil
|
|
34
|
-
end
|
|
26
|
+
ENV['PARALLEL_PID_FILE'] = f.path
|
|
27
|
+
# Pids object should be created before threads will start adding pids to it
|
|
28
|
+
# Otherwise we would have to use Mutex to prevent creation of several instances
|
|
29
|
+
@pids = pids
|
|
30
|
+
yield
|
|
31
|
+
ensure
|
|
32
|
+
ENV['PARALLEL_PID_FILE'] = nil
|
|
33
|
+
@pids = nil
|
|
35
34
|
end
|
|
36
35
|
end
|
|
37
36
|
|
|
@@ -57,7 +56,8 @@ module ParallelTests
|
|
|
57
56
|
until !File.directory?(current) || current == previous
|
|
58
57
|
filename = File.join(current, "Gemfile")
|
|
59
58
|
return true if File.exist?(filename)
|
|
60
|
-
|
|
59
|
+
previous = current
|
|
60
|
+
current = File.expand_path("..", current)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
false
|
data/lib/parallel_tests/cli.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'optparse'
|
|
2
3
|
require 'tempfile'
|
|
3
4
|
require 'parallel_tests'
|
|
@@ -14,7 +15,7 @@ module ParallelTests
|
|
|
14
15
|
ENV['DISABLE_SPRING'] ||= '1'
|
|
15
16
|
|
|
16
17
|
num_processes = ParallelTests.determine_number_of_processes(options[:count])
|
|
17
|
-
num_processes
|
|
18
|
+
num_processes *= (options[:multiply] || 1)
|
|
18
19
|
|
|
19
20
|
options[:first_is_1] ||= first_is_1?
|
|
20
21
|
|
|
@@ -56,12 +57,12 @@ module ParallelTests
|
|
|
56
57
|
def run_tests_in_parallel(num_processes, options)
|
|
57
58
|
test_results = nil
|
|
58
59
|
|
|
59
|
-
run_tests_proc = ->
|
|
60
|
+
run_tests_proc = -> do
|
|
60
61
|
groups = @runner.tests_in_groups(options[:files], num_processes, options)
|
|
61
|
-
groups.reject!
|
|
62
|
+
groups.reject!(&:empty?)
|
|
62
63
|
|
|
63
64
|
test_results = if options[:only_group]
|
|
64
|
-
groups_to_run = options[:only_group].
|
|
65
|
+
groups_to_run = options[:only_group].map { |i| groups[i - 1] }.compact
|
|
65
66
|
report_number_of_tests(groups_to_run) unless options[:quiet]
|
|
66
67
|
execute_in_parallel(groups_to_run, groups_to_run.size, options) do |group|
|
|
67
68
|
run_tests(group, groups_to_run.index(group), 1, options)
|
|
@@ -75,7 +76,7 @@ module ParallelTests
|
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
report_results(test_results, options) unless options[:quiet]
|
|
78
|
-
|
|
79
|
+
end
|
|
79
80
|
|
|
80
81
|
if options[:quiet]
|
|
81
82
|
run_tests_proc.call
|
|
@@ -83,12 +84,23 @@ module ParallelTests
|
|
|
83
84
|
report_time_taken(&run_tests_proc)
|
|
84
85
|
end
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
if any_test_failed?(test_results)
|
|
88
|
+
warn final_fail_message
|
|
89
|
+
|
|
90
|
+
# return the highest exit status to allow sub-processes to send things other than 1
|
|
91
|
+
exit_status = if options[:highest_exit_status]
|
|
92
|
+
test_results.map { |data| data.fetch(:exit_status) }.max
|
|
93
|
+
else
|
|
94
|
+
1
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
exit exit_status
|
|
98
|
+
end
|
|
87
99
|
end
|
|
88
100
|
|
|
89
101
|
def run_tests(group, process_number, num_processes, options)
|
|
90
102
|
if group.empty?
|
|
91
|
-
{:
|
|
103
|
+
{ stdout: '', exit_status: 0, command: '', seed: nil }
|
|
92
104
|
else
|
|
93
105
|
@runner.run_tests(group, process_number, num_processes, options)
|
|
94
106
|
end
|
|
@@ -104,18 +116,16 @@ module ParallelTests
|
|
|
104
116
|
|
|
105
117
|
def lock(lockfile)
|
|
106
118
|
File.open(lockfile) do |lock|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
lock.flock File::LOCK_UN
|
|
113
|
-
end
|
|
119
|
+
lock.flock File::LOCK_EX
|
|
120
|
+
yield
|
|
121
|
+
ensure
|
|
122
|
+
# This shouldn't be necessary, but appears to be
|
|
123
|
+
lock.flock File::LOCK_UN
|
|
114
124
|
end
|
|
115
125
|
end
|
|
116
126
|
|
|
117
127
|
def report_results(test_results, options)
|
|
118
|
-
results = @runner.find_results(test_results.map { |result| result[:stdout] }*"")
|
|
128
|
+
results = @runner.find_results(test_results.map { |result| result[:stdout] } * "")
|
|
119
129
|
puts ""
|
|
120
130
|
puts @runner.summarize_results(results)
|
|
121
131
|
|
|
@@ -140,20 +150,31 @@ module ParallelTests
|
|
|
140
150
|
def report_number_of_tests(groups)
|
|
141
151
|
name = @runner.test_file_name
|
|
142
152
|
num_processes = groups.size
|
|
143
|
-
num_tests = groups.map(&:size).
|
|
153
|
+
num_tests = groups.map(&:size).sum
|
|
144
154
|
tests_per_process = (num_processes == 0 ? 0 : num_tests / num_processes)
|
|
145
|
-
puts "#{num_processes}
|
|
155
|
+
puts "#{pluralize(num_processes, 'process')} for #{pluralize(num_tests, name)}, ~ #{pluralize(tests_per_process, name)} per process"
|
|
146
156
|
end
|
|
147
157
|
|
|
148
|
-
|
|
158
|
+
def pluralize(n, singular)
|
|
159
|
+
if n == 1
|
|
160
|
+
"1 #{singular}"
|
|
161
|
+
elsif singular.end_with?('s', 'sh', 'ch', 'x', 'z')
|
|
162
|
+
"#{n} #{singular}es"
|
|
163
|
+
else
|
|
164
|
+
"#{n} #{singular}s"
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# exit with correct status code so rake parallel:test && echo 123 works
|
|
149
169
|
def any_test_failed?(test_results)
|
|
150
170
|
test_results.any? { |result| result[:exit_status] != 0 }
|
|
151
171
|
end
|
|
152
172
|
|
|
153
173
|
def parse_options!(argv)
|
|
174
|
+
newline_padding = " " * 37
|
|
154
175
|
options = {}
|
|
155
176
|
OptionParser.new do |opts|
|
|
156
|
-
opts.banner =
|
|
177
|
+
opts.banner = <<~BANNER
|
|
157
178
|
Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
|
|
158
179
|
|
|
159
180
|
[optional] Only selected files & folders:
|
|
@@ -167,61 +188,78 @@ module ParallelTests
|
|
|
167
188
|
opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
|
|
168
189
|
opts.on("-p", "--pattern [PATTERN]", "run tests matching this regex pattern") { |pattern| options[:pattern] = /#{pattern}/ }
|
|
169
190
|
opts.on("--exclude-pattern", "--exclude-pattern [PATTERN]", "exclude tests matching this regex pattern") { |pattern| options[:exclude_pattern] = /#{pattern}/ }
|
|
170
|
-
opts.on(
|
|
171
|
-
group
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
191
|
+
opts.on(
|
|
192
|
+
"--group-by [TYPE]",
|
|
193
|
+
<<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
|
|
194
|
+
group tests by:
|
|
195
|
+
found - order of finding files
|
|
196
|
+
steps - number of cucumber/spinach steps
|
|
197
|
+
scenarios - individual cucumber scenarios
|
|
198
|
+
filesize - by size of the file
|
|
199
|
+
runtime - info from runtime log
|
|
200
|
+
default - runtime when runtime log is filled otherwise filesize
|
|
178
201
|
TEXT
|
|
179
|
-
|
|
180
|
-
opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run")
|
|
181
|
-
|
|
182
|
-
opts.on("-s [PATTERN]", "--single [PATTERN]",
|
|
183
|
-
"Run all matching files in the same process") do |pattern|
|
|
184
|
-
|
|
185
|
-
options[:single_process] ||= []
|
|
186
|
-
options[:single_process] << /#{pattern}/
|
|
202
|
+
) { |type| options[:group_by] = type.to_sym }
|
|
203
|
+
opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") do |multiply|
|
|
204
|
+
options[:multiply] = multiply
|
|
187
205
|
end
|
|
188
206
|
|
|
189
|
-
opts.on("-
|
|
190
|
-
|
|
207
|
+
opts.on("-s [PATTERN]", "--single [PATTERN]", "Run all matching files in the same process") do |pattern|
|
|
208
|
+
(options[:single_process] ||= []) << /#{pattern}/
|
|
209
|
+
end
|
|
191
210
|
|
|
211
|
+
opts.on("-i", "--isolate", "Do not run any other tests in the group used by --single(-s)") do
|
|
192
212
|
options[:isolate] = true
|
|
193
213
|
end
|
|
194
214
|
|
|
195
|
-
opts.on(
|
|
215
|
+
opts.on(
|
|
216
|
+
"--isolate-n [PROCESSES]",
|
|
196
217
|
Integer,
|
|
197
|
-
"Use 'isolate' singles with number of processes, default: 1."
|
|
198
|
-
|
|
218
|
+
"Use 'isolate' singles with number of processes, default: 1."
|
|
219
|
+
) { |n| options[:isolate_count] = n }
|
|
220
|
+
|
|
221
|
+
opts.on("--highest-exit-status", "Exit with the highest exit status provided by test run(s)") do
|
|
222
|
+
options[:highest_exit_status] = true
|
|
199
223
|
end
|
|
200
224
|
|
|
201
|
-
opts.on(
|
|
225
|
+
opts.on(
|
|
226
|
+
"--specify-groups [SPECS]",
|
|
227
|
+
<<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
|
|
228
|
+
Use 'specify-groups' if you want to specify multiple specs running in multiple
|
|
229
|
+
processes in a specific formation. Commas indicate specs in the same process,
|
|
230
|
+
pipes indicate specs in a new process. Cannot use with --single, --isolate, or
|
|
231
|
+
--isolate-n. Ex.
|
|
232
|
+
$ parallel_tests -n 3 . --specify-groups '1_spec.rb,2_spec.rb|3_spec.rb'
|
|
233
|
+
Process 1 will contain 1_spec.rb and 2_spec.rb
|
|
234
|
+
Process 2 will contain 3_spec.rb
|
|
235
|
+
Process 3 will contain all other specs
|
|
236
|
+
TEXT
|
|
237
|
+
) { |groups| options[:specify_groups] = groups }
|
|
238
|
+
|
|
239
|
+
opts.on("--only-group INT[,INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
|
|
202
240
|
|
|
203
241
|
opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |path| options[:execute] = path }
|
|
204
242
|
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg.lstrip }
|
|
205
243
|
opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
abort
|
|
211
|
-
end
|
|
244
|
+
@runner = load_runner(type)
|
|
245
|
+
rescue NameError, LoadError => e
|
|
246
|
+
puts "Runner for `#{type}` type has not been found! (#{e})"
|
|
247
|
+
abort
|
|
212
248
|
end
|
|
213
|
-
opts.on(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
opts.on(
|
|
250
|
+
"--suffix [PATTERN]",
|
|
251
|
+
<<~TEXT.rstrip.split("\n").join("\n#{newline_padding}")
|
|
252
|
+
override built in test file pattern (should match suffix):
|
|
253
|
+
'_spec\.rb$' - matches rspec files
|
|
254
|
+
'_(test|spec).rb$' - matches test or spec files
|
|
217
255
|
TEXT
|
|
218
|
-
|
|
256
|
+
) { |pattern| options[:suffix] = /#{pattern}/ }
|
|
219
257
|
opts.on("--serialize-stdout", "Serialize stdout output, nothing will be written until everything is done") { options[:serialize_stdout] = true }
|
|
220
258
|
opts.on("--prefix-output-with-test-env-number", "Prefixes test env number to the output when not using --serialize-stdout") { options[:prefix_output_with_test_env_number] = true }
|
|
221
259
|
opts.on("--combine-stderr", "Combine stderr into stdout, useful in conjunction with --serialize-stdout") { options[:combine_stderr] = true }
|
|
222
260
|
opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec") { options[:non_parallel] = true }
|
|
223
261
|
opts.on("--no-symlinks", "Do not traverse symbolic links to find test files") { options[:symlinks] = false }
|
|
224
|
-
opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern')
|
|
262
|
+
opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern') { |arg| options[:ignore_tag_pattern] = arg }
|
|
225
263
|
opts.on("--nice", "execute test commands with low priority.") { options[:nice] = true }
|
|
226
264
|
opts.on("--runtime-log [PATH]", "Location of previously recorded test runtimes") { |path| options[:runtime_log] = path }
|
|
227
265
|
opts.on("--allowed-missing [INT]", Integer, "Allowed percentage of missing runtimes (default = 50)") { |percent| options[:allowed_missing_percent] = percent }
|
|
@@ -232,13 +270,17 @@ module ParallelTests
|
|
|
232
270
|
opts.on("--verbose-process-command", "Displays only the command that will be executed by each process") { options[:verbose_process_command] = true }
|
|
233
271
|
opts.on("--verbose-rerun-command", "When there are failures, displays the command executed by each process that failed") { options[:verbose_rerun_command] = true }
|
|
234
272
|
opts.on("--quiet", "Print only tests output") { options[:quiet] = true }
|
|
235
|
-
opts.on("-v", "--version", "Show Version")
|
|
236
|
-
|
|
273
|
+
opts.on("-v", "--version", "Show Version") do
|
|
274
|
+
puts ParallelTests::VERSION
|
|
275
|
+
exit 0
|
|
276
|
+
end
|
|
277
|
+
opts.on("-h", "--help", "Show this.") do
|
|
278
|
+
puts opts
|
|
279
|
+
exit 0
|
|
280
|
+
end
|
|
237
281
|
end.parse!(argv)
|
|
238
282
|
|
|
239
|
-
if options[:verbose] && options[:quiet]
|
|
240
|
-
raise "Both options are mutually exclusive: verbose & quiet"
|
|
241
|
-
end
|
|
283
|
+
raise "Both options are mutually exclusive: verbose & quiet" if options[:verbose] && options[:quiet]
|
|
242
284
|
|
|
243
285
|
if options[:count] == 0
|
|
244
286
|
options.delete(:count)
|
|
@@ -247,7 +289,14 @@ module ParallelTests
|
|
|
247
289
|
|
|
248
290
|
files, remaining = extract_file_paths(argv)
|
|
249
291
|
unless options[:execute]
|
|
250
|
-
|
|
292
|
+
if files.empty?
|
|
293
|
+
default_test_folder = @runner.default_test_folder
|
|
294
|
+
if File.directory?(default_test_folder)
|
|
295
|
+
files = [default_test_folder]
|
|
296
|
+
else
|
|
297
|
+
abort "Pass files or folders to run"
|
|
298
|
+
end
|
|
299
|
+
end
|
|
251
300
|
options[:files] = files.map { |file_path| Pathname.new(file_path).cleanpath.to_s }
|
|
252
301
|
end
|
|
253
302
|
|
|
@@ -255,12 +304,18 @@ module ParallelTests
|
|
|
255
304
|
|
|
256
305
|
options[:group_by] ||= :filesize if options[:only_group]
|
|
257
306
|
|
|
258
|
-
|
|
307
|
+
if options[:group_by] == :found && options[:single_process]
|
|
308
|
+
raise "--group-by found and --single-process are not supported"
|
|
309
|
+
end
|
|
259
310
|
allowed = [:filesize, :runtime, :found]
|
|
260
311
|
if !allowed.include?(options[:group_by]) && options[:only_group]
|
|
261
312
|
raise "--group-by #{allowed.join(" or ")} is required for --only-group"
|
|
262
313
|
end
|
|
263
314
|
|
|
315
|
+
if options[:specify_groups] && (options.keys & [:single_process, :isolate, :isolate_count]).any?
|
|
316
|
+
raise "Can't pass --specify-groups with any of these keys: --single, --isolate, or --isolate-n"
|
|
317
|
+
end
|
|
318
|
+
|
|
264
319
|
options
|
|
265
320
|
end
|
|
266
321
|
|
|
@@ -272,7 +327,7 @@ module ParallelTests
|
|
|
272
327
|
|
|
273
328
|
def extract_test_options(argv)
|
|
274
329
|
dash_index = argv.index("--") || -1
|
|
275
|
-
argv[dash_index+1..-1]
|
|
330
|
+
argv[dash_index + 1..-1]
|
|
276
331
|
end
|
|
277
332
|
|
|
278
333
|
def append_test_options(options, argv)
|
|
@@ -292,7 +347,7 @@ module ParallelTests
|
|
|
292
347
|
|
|
293
348
|
def execute_shell_command_in_parallel(command, num_processes, options)
|
|
294
349
|
runs = if options[:only_group]
|
|
295
|
-
options[:only_group].map{|g| g - 1}
|
|
350
|
+
options[:only_group].map { |g| g - 1 }
|
|
296
351
|
else
|
|
297
352
|
(0...num_processes).to_a
|
|
298
353
|
end
|
|
@@ -311,13 +366,13 @@ module ParallelTests
|
|
|
311
366
|
abort if results.any? { |r| r[:exit_status] != 0 }
|
|
312
367
|
end
|
|
313
368
|
|
|
314
|
-
def report_time_taken
|
|
315
|
-
seconds = ParallelTests.delta
|
|
369
|
+
def report_time_taken(&block)
|
|
370
|
+
seconds = ParallelTests.delta(&block).to_i
|
|
316
371
|
puts "\nTook #{seconds} seconds#{detailed_duration(seconds)}"
|
|
317
372
|
end
|
|
318
373
|
|
|
319
374
|
def detailed_duration(seconds)
|
|
320
|
-
parts = [
|
|
375
|
+
parts = [seconds / 3600, seconds % 3600 / 60, seconds % 60].drop_while(&:zero?)
|
|
321
376
|
return if parts.size < 2
|
|
322
377
|
parts = parts.map { |i| "%02d" % i }.join(':').sub(/^0/, '')
|
|
323
378
|
" (#{parts})"
|