vinted-parallel_tests 0.13.3 → 1.7.0.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 +86 -47
- data/bin/parallel_cucumber +5 -1
- data/bin/parallel_rspec +5 -1
- data/bin/parallel_spinach +9 -0
- data/bin/parallel_test +5 -1
- data/lib/parallel_tests.rb +15 -2
- data/lib/parallel_tests/cli.rb +115 -35
- data/lib/parallel_tests/cucumber/failures_logger.rb +9 -7
- data/lib/parallel_tests/cucumber/runner.rb +16 -77
- data/lib/parallel_tests/cucumber/scenario_line_logger.rb +52 -0
- data/lib/parallel_tests/cucumber/scenarios.rb +34 -0
- data/lib/parallel_tests/{cucumber → gherkin}/io.rb +1 -1
- data/lib/parallel_tests/{cucumber/gherkin_listener.rb → gherkin/listener.rb} +11 -6
- data/lib/parallel_tests/gherkin/runner.rb +116 -0
- data/lib/parallel_tests/{cucumber → gherkin}/runtime_logger.rb +2 -2
- data/lib/parallel_tests/grouper.rb +34 -17
- data/lib/parallel_tests/rspec/failures_logger.rb +22 -14
- data/lib/parallel_tests/rspec/logger_base.rb +5 -1
- data/lib/parallel_tests/rspec/runner.rb +5 -4
- data/lib/parallel_tests/rspec/runtime_logger.rb +10 -5
- data/lib/parallel_tests/rspec/summary_logger.rb +11 -11
- data/lib/parallel_tests/spinach/runner.rb +19 -0
- data/lib/parallel_tests/tasks.rb +41 -18
- data/lib/parallel_tests/test/runner.rb +80 -28
- data/lib/parallel_tests/test/runtime_logger.rb +86 -55
- data/lib/parallel_tests/version.rb +1 -1
- metadata +18 -35
- data/.gitignore +0 -2
- data/.rspec +0 -2
- data/.travis.yml +0 -6
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -48
- data/Rakefile +0 -6
- data/ReadmeRails2.md +0 -48
- data/parallel_tests.gemspec +0 -14
- data/spec/integration_spec.rb +0 -285
- data/spec/parallel_tests/cli_spec.rb +0 -71
- data/spec/parallel_tests/cucumber/failure_logger_spec.rb +0 -43
- data/spec/parallel_tests/cucumber/gherkin_listener_spec.rb +0 -97
- data/spec/parallel_tests/cucumber/runner_spec.rb +0 -179
- data/spec/parallel_tests/grouper_spec.rb +0 -52
- data/spec/parallel_tests/rspec/failures_logger_spec.rb +0 -82
- data/spec/parallel_tests/rspec/runner_spec.rb +0 -187
- data/spec/parallel_tests/rspec/runtime_logger_spec.rb +0 -126
- data/spec/parallel_tests/rspec/summary_logger_spec.rb +0 -37
- data/spec/parallel_tests/tasks_spec.rb +0 -151
- data/spec/parallel_tests/test/runner_spec.rb +0 -413
- data/spec/parallel_tests/test/runtime_logger_spec.rb +0 -90
- data/spec/parallel_tests_spec.rb +0 -137
- data/spec/spec_helper.rb +0 -157
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c24065e6ecc117e7e693090d95bf2233b28bb83b
|
4
|
+
data.tar.gz: 959293ff1bc3211d8ef3f302f79e82313a1f8f50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9a7b68b7a4c0ee89c2d6b3ad829a19eda204d383b5322131af6cdc46c4befb8836719bf2711b80445b9832283570707057eaf856285f2fe655534cae32dfc74
|
7
|
+
data.tar.gz: 58642970a41d300b6de94a702ef7891a6151e50f6439501133fb93fe3185f2af587c946e030eef4161347b910e953b65b452e3317d38b7b1a472e062ca5202e4
|
data/Readme.md
CHANGED
@@ -1,36 +1,28 @@
|
|
1
|
-
|
2
|
-
ParallelTests splits tests into even groups(by number of tests or runtime) and runs each group in a single process with its own database.
|
1
|
+
# parallel_tests
|
3
2
|
|
4
|
-
[
|
3
|
+
[](https://rubygems.org/gems/parallel_tests)
|
4
|
+
[](https://travis-ci.org/grosser/parallel_tests/builds)
|
5
|
+
|
6
|
+
Speedup Test::Unit + RSpec + Cucumber + Spinach by running parallel on multiple CPU cores.<br/>
|
7
|
+
ParallelTests splits tests into even groups (by number of lines or runtime) and runs each group in a single process with its own database.
|
5
8
|
|
6
9
|
Setup for Rails
|
7
10
|
===============
|
8
11
|
[RailsCasts episode #413 Fast Tests](http://railscasts.com/episodes/413-fast-tests)
|
9
|
-
[still using Rails 2?](https://github.com/grosser/parallel_tests/blob/master/ReadmeRails2.md)
|
10
12
|
|
11
13
|
### Install
|
12
|
-
If you use RSpec: ensure you got >= 2.4
|
13
|
-
|
14
|
-
As gem
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
# add to Gemfile
|
18
|
-
gem "parallel_tests", :group => :development
|
19
|
-
```
|
20
|
-
OR as plugin
|
21
|
-
|
22
|
-
rails plugin install git://github.com/grosser/parallel_tests.git
|
23
14
|
|
24
15
|
```ruby
|
25
|
-
#
|
26
|
-
gem "
|
16
|
+
# Gemfile
|
17
|
+
gem "parallel_tests", group: :development
|
27
18
|
```
|
28
19
|
|
29
20
|
### Add to `config/database.yml`
|
21
|
+
|
30
22
|
ParallelTests uses 1 database per test-process.
|
31
23
|
<table>
|
32
24
|
<tr><td>Process number</td><td>1</td><td>2</td><td>3</td></tr>
|
33
|
-
<tr><td
|
25
|
+
<tr><td>ENV['TEST_ENV_NUMBER']</td><td>''</td><td>'2'</td><td>'3'</td></tr>
|
34
26
|
</table>
|
35
27
|
|
36
28
|
```yaml
|
@@ -48,6 +40,7 @@ test:
|
|
48
40
|
rake parallel:test # Test::Unit
|
49
41
|
rake parallel:spec # RSpec
|
50
42
|
rake parallel:features # Cucumber
|
43
|
+
rake parallel:features-spinach # Spinach
|
51
44
|
|
52
45
|
rake parallel:test[1] --> force 1 CPU --> 86 seconds
|
53
46
|
rake parallel:test --> got 2 CPUs? --> 47 seconds
|
@@ -97,37 +90,44 @@ end
|
|
97
90
|
Loggers
|
98
91
|
===================
|
99
92
|
|
100
|
-
Even
|
101
|
-
|
93
|
+
Even test group run-times
|
94
|
+
-------------------------
|
95
|
+
|
96
|
+
### RSpec
|
102
97
|
|
103
|
-
|
98
|
+
Add the `RuntimeLogger` to log how long each test takes to run.
|
99
|
+
This log file will be loaded on the next test run, and the tests will be grouped
|
100
|
+
so that each process should finish around the same time.
|
104
101
|
|
105
102
|
Rspec: Add to your `.rspec_parallel` (or `.rspec`) :
|
106
103
|
|
107
|
-
If installed as plugin: -I vendor/plugins/parallel_tests/lib
|
108
104
|
--format progress
|
109
105
|
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
|
110
106
|
|
111
|
-
Test::Unit
|
107
|
+
### Test::Unit & Minitest 4/5
|
108
|
+
|
109
|
+
Add to your `test_helper.rb`:
|
112
110
|
```ruby
|
113
|
-
require 'parallel_tests/test/runtime_logger'
|
111
|
+
require 'parallel_tests/test/runtime_logger' if ENV['RECORD_RUNTIME']
|
114
112
|
```
|
115
113
|
|
114
|
+
results will be logged to tmp/parallel_runtime_test.log when `RECORD_RUNTIME` is set,
|
115
|
+
so it is not always required or overwritten.
|
116
|
+
|
116
117
|
RSpec: SummaryLogger
|
117
118
|
--------------------
|
118
119
|
|
119
|
-
|
120
|
+
Log the test output without the different processes overwriting each other.
|
120
121
|
|
121
122
|
Add the following to your `.rspec_parallel` (or `.rspec`) :
|
122
123
|
|
123
|
-
If installed as plugin: -I vendor/plugins/parallel_tests/lib
|
124
124
|
--format progress
|
125
125
|
--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log
|
126
126
|
|
127
127
|
RSpec: FailuresLogger
|
128
128
|
-----------------------
|
129
129
|
|
130
|
-
|
130
|
+
Produce pasteable command-line snippets for each failed example.
|
131
131
|
|
132
132
|
E.g.
|
133
133
|
|
@@ -135,14 +135,13 @@ E.g.
|
|
135
135
|
|
136
136
|
Add the following to your `.rspec_parallel` (or `.rspec`) :
|
137
137
|
|
138
|
-
If installed as plugin: -I vendor/plugins/parallel_tests/lib
|
139
138
|
--format progress
|
140
139
|
--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log
|
141
140
|
|
142
141
|
Cucumber: FailuresLogger
|
143
142
|
-----------------------
|
144
143
|
|
145
|
-
|
144
|
+
Log failed cucumber scenarios to the specified file. The filename can be passed to cucumber, prefixed with '@' to rerun failures.
|
146
145
|
|
147
146
|
Usage:
|
148
147
|
|
@@ -152,47 +151,65 @@ Or add the formatter to the `parallel:` profile of your `cucumber.yml`:
|
|
152
151
|
|
153
152
|
parallel: --format progress --format ParallelTests::Cucumber::FailuresLogger --out tmp/cucumber_failures.log
|
154
153
|
|
154
|
+
Note if your `cucumber.yml` default profile uses `<%= std_opts %>` you may need to insert this as follows `parallel: <%= std_opts %> --format progress...`
|
155
155
|
|
156
156
|
To rerun failures:
|
157
157
|
|
158
|
-
|
158
|
+
cucumber @tmp/cucumber_failures.log
|
159
159
|
|
160
160
|
Setup for non-rails
|
161
161
|
===================
|
162
|
+
|
162
163
|
gem install parallel_tests
|
163
164
|
# go to your project dir
|
164
165
|
parallel_test test/
|
165
166
|
parallel_rspec spec/
|
166
167
|
parallel_cucumber features/
|
168
|
+
parallel_spinach features/
|
167
169
|
|
168
|
-
- use ENV['TEST_ENV_NUMBER'] inside your tests to select separate db/memcache/etc.
|
170
|
+
- use `ENV['TEST_ENV_NUMBER']` inside your tests to select separate db/memcache/etc.
|
169
171
|
- Only run selected files & folders:
|
170
172
|
|
171
|
-
parallel_test test/bar test/baz/foo_text.rb
|
173
|
+
`parallel_test test/bar test/baz/foo_text.rb`
|
174
|
+
|
175
|
+
- Pass test-options and files via `--`:
|
176
|
+
|
177
|
+
`parallel_test -- -t acceptance -f progress -- spec/foo_spec.rb spec/acceptance`
|
172
178
|
|
173
179
|
Options are:
|
180
|
+
<!-- copy output from bundle exec ./bin/parallel_test -h -->
|
174
181
|
|
175
182
|
-n [PROCESSES] How many processes to use, default: available CPUs
|
176
183
|
-p, --pattern [PATTERN] run tests matching this pattern
|
177
184
|
--group-by [TYPE] group tests by:
|
178
185
|
found - order of finding files
|
179
|
-
steps - number of cucumber steps
|
180
|
-
|
186
|
+
steps - number of cucumber/spinach steps
|
187
|
+
scenarios - individual cucumber scenarios
|
188
|
+
filesize - by size of the file
|
189
|
+
runtime - info from runtime log
|
190
|
+
default - runtime when runtime log is filled otherwise filesize
|
181
191
|
-m, --multiply-processes [FLOAT] use given number as a multiplier of processes to run
|
182
192
|
-s, --single [PATTERN] Run all matching files in the same process
|
183
193
|
-i, --isolate Do not run any other tests in the group used by --single(-s)
|
184
|
-
|
194
|
+
--only-group INT[, INT]
|
195
|
+
-e, --exec [COMMAND] execute this code parallel and with ENV['TEST_ENV_NUMBER']
|
185
196
|
-o, --test-options '[OPTIONS]' execute test commands with those options
|
186
|
-
-t, --type [TYPE] test(default) / rspec / cucumber
|
197
|
+
-t, --type [TYPE] test(default) / rspec / cucumber / spinach
|
198
|
+
--suffix [PATTERN] override built in test file pattern (should match suffix):
|
199
|
+
'_spec.rb$' - matches rspec files
|
200
|
+
'_(test|spec).rb$' - matches test or spec files
|
187
201
|
--serialize-stdout Serialize stdout output, nothing will be written until everything is done
|
202
|
+
--combine-stderr Combine stderr into stdout, useful in conjunction with --serialize-stdout
|
188
203
|
--non-parallel execute same commands but do not in parallel, needs --exec
|
189
204
|
--no-symlinks Do not traverse symbolic links to find test files
|
190
205
|
--ignore-tags [PATTERN] When counting steps ignore scenarios with tags that match this pattern
|
191
206
|
--nice execute test commands with low priority.
|
207
|
+
--runtime-log [PATH] Location of previously recorded test runtimes
|
208
|
+
--verbose Print more output
|
192
209
|
-v, --version Show Version
|
193
210
|
-h, --help Show this.
|
194
211
|
|
195
|
-
You can run any kind of code in parallel with -e / --
|
212
|
+
You can run any kind of code in parallel with -e / --exec
|
196
213
|
|
197
214
|
parallel_test -n 5 -e 'ruby -e "puts %[hello from process #{ENV[:TEST_ENV_NUMBER.to_s].inspect}]"'
|
198
215
|
hello from process "2"
|
@@ -210,11 +227,10 @@ You can run any kind of code in parallel with -e / --execute
|
|
210
227
|
TIPS
|
211
228
|
====
|
212
229
|
- [RSpec] add a `.rspec_parallel` to use different options, e.g. **no --drb**
|
213
|
-
-
|
214
|
-
- [
|
215
|
-
- [RSpec] remove --loadby from you spec/*.opts
|
230
|
+
- Spring does not work with parallel_tests, use `DISABLE_SPRING=1 rake parallel:spec` if you have spring hardcoded in your binaries
|
231
|
+
- [RSpec] remove `--loadby` from `.rspec`
|
216
232
|
- [RSpec] Instantly see failures (instead of just a red F) with [rspec-instafail](https://github.com/grosser/rspec-instafail)
|
217
|
-
- [
|
233
|
+
- [RSpec] use [rspec-retry](https://github.com/NoRedInk/rspec-retry) (not rspec-rerun) to rerun failed tests.
|
218
234
|
- [Cucumber] add a `parallel: foo` profile to your `config/cucumber.yml` and it will be used to run parallel tests
|
219
235
|
- [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
|
220
236
|
- [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
|
@@ -223,13 +239,16 @@ TIPS
|
|
223
239
|
- `export PARALLEL_TEST_PROCESSORS=X` in your environment and parallel_tests will use this number of processors by default
|
224
240
|
- [ZSH] use quotes to use rake arguments `rake "parallel:prepare[3]"`
|
225
241
|
- [email_spec and/or action_mailer_cache_delivery](https://github.com/grosser/parallel_tests/wiki)
|
226
|
-
- [Memcached] use different namespaces e.g. `config.cache_store = ..., :
|
242
|
+
- [Memcached] use different namespaces e.g. `config.cache_store = ..., namespace: "test_#{ENV['TEST_ENV_NUMBER']}"`
|
243
|
+
- [zeus-parallel_tests](https://github.com/sevos/zeus-parallel_tests)
|
244
|
+
- [Distributed parallel test (e.g. Travis Support)](https://github.com/grosser/parallel_tests/wiki/Distributed-Parallel-Tests-and-Travis-Support)
|
245
|
+
- Debug errors that only happen with multiple files using `--verbose` and [cleanser](https://github.com/grosser/cleanser)
|
246
|
+
- Shell alias: `alias prspec='parallel_rspec -m 2 --'`
|
247
|
+
- Contribute your own gotaches to the [Wiki](https://github.com/grosser/parallel_tests/wiki) or even better open a PR :)
|
227
248
|
|
228
249
|
TODO
|
229
250
|
====
|
230
|
-
- make tests consistently pass with `--order random` in .rspec
|
231
251
|
- fix tests vs cucumber >= 1.2 `unknown option --format`
|
232
|
-
- add integration tests for the rake tasks, maybe generate a rails project ...
|
233
252
|
- add unit tests for cucumber runtime formatter
|
234
253
|
- make windows compatible
|
235
254
|
|
@@ -237,7 +256,7 @@ Authors
|
|
237
256
|
====
|
238
257
|
inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-parallelize-your-rspec-suite)
|
239
258
|
|
240
|
-
### [Contributors](
|
259
|
+
### [Contributors](https://github.com/grosser/parallel_tests/contributors)
|
241
260
|
- [Charles Finkel](http://charlesfinkel.com/)
|
242
261
|
- [Indrek Juhkam](http://urgas.eu)
|
243
262
|
- [Jason Morrison](http://jayunit.net)
|
@@ -286,8 +305,28 @@ inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-
|
|
286
305
|
- [Iain Beeston](https://github.com/iainbeeston)
|
287
306
|
- [Alejandro Pulver](https://github.com/alepulver)
|
288
307
|
- [Felix Clack](https://github.com/felixclack)
|
308
|
+
- [Izaak Alpert](https://github.com/karlhungus)
|
309
|
+
- [Micah Geisel](https://github.com/botandrose)
|
310
|
+
- [Exoth](https://github.com/Exoth)
|
311
|
+
- [sidfarkus](https://github.com/sidfarkus)
|
312
|
+
- [Colin Harris](https://github.com/aberant)
|
313
|
+
- [Wataru MIYAGUNI](https://github.com/gongo)
|
314
|
+
- [Brandon Turner](https://github.com/blt04)
|
315
|
+
- [Matt Hodgson](https://github.com/mhodgson)
|
316
|
+
- [bicarbon8](https://github.com/bicarbon8)
|
317
|
+
- [seichner](https://github.com/seichner)
|
318
|
+
- [Matt Southerden](https://github.com/mattsoutherden)
|
319
|
+
- [Stanislaw Wozniak](https://github.com/sponte)
|
320
|
+
- [Dmitry Polushkin](https://github.com/dmitry)
|
321
|
+
- [Samer Masry](https://github.com/smasry)
|
322
|
+
- [Volodymyr Mykhailyk](https:/github.com/volodymyr-mykhailyk)
|
323
|
+
- [Mike Mueller](https://github.com/mmueller)
|
324
|
+
- [Aaron Jensen](https://github.com/aaronjensen)
|
325
|
+
- [Ed Slocomb](https://github.com/edslocomb)
|
326
|
+
- [Cezary Baginski](https://github.com/e2)
|
327
|
+
- [Marius Ioana](https://github.com/mariusioana)
|
328
|
+
|
289
329
|
|
290
330
|
[Michael Grosser](http://grosser.it)<br/>
|
291
331
|
michael@grosser.it<br/>
|
292
|
-
License: MIT
|
293
|
-
[](https://travis-ci.org/grosser/parallel_tests)
|
332
|
+
License: MIT
|
data/bin/parallel_cucumber
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
|
3
|
+
# enable local usage from cloned repo
|
4
|
+
root = File.expand_path("../..", __FILE__)
|
5
|
+
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
6
|
+
|
3
7
|
require "parallel_tests"
|
4
8
|
|
5
9
|
ParallelTests::CLI.new.run(["--type", "cucumber"] + ARGV)
|
data/bin/parallel_rspec
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
|
3
|
+
# enable local usage from cloned repo
|
4
|
+
root = File.expand_path("../..", __FILE__)
|
5
|
+
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
6
|
+
|
3
7
|
require "parallel_tests"
|
4
8
|
|
5
9
|
ParallelTests::CLI.new.run(["--type", "rspec"] + ARGV)
|
data/bin/parallel_test
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
|
3
|
+
# enable local usage from cloned repo
|
4
|
+
root = File.expand_path("../..", __FILE__)
|
5
|
+
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
6
|
+
|
3
7
|
require "parallel_tests"
|
4
8
|
|
5
9
|
ParallelTests::CLI.new.run(["--type", "test"] + ARGV)
|
data/lib/parallel_tests.rb
CHANGED
@@ -1,8 +1,15 @@
|
|
1
1
|
require "parallel"
|
2
2
|
require "parallel_tests/railtie" if defined? Rails::Railtie
|
3
|
+
require "rbconfig"
|
3
4
|
|
4
5
|
module ParallelTests
|
5
|
-
|
6
|
+
WINDOWS = (RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/)
|
7
|
+
GREP_PROCESSES_COMMAND = \
|
8
|
+
if WINDOWS
|
9
|
+
"wmic process get commandline | findstr TEST_ENV_NUMBER | find /c \"TEST_ENV_NUMBER=\" 2>&1"
|
10
|
+
else
|
11
|
+
"ps -ef | grep [T]EST_ENV_NUMBER= 2>&1"
|
12
|
+
end
|
6
13
|
|
7
14
|
autoload :CLI, "parallel_tests/cli"
|
8
15
|
autoload :VERSION, "parallel_tests/version"
|
@@ -26,7 +33,7 @@ module ParallelTests
|
|
26
33
|
|
27
34
|
until !File.directory?(current) || current == previous
|
28
35
|
filename = File.join(current, "Gemfile")
|
29
|
-
return true if File.
|
36
|
+
return true if File.exist?(filename)
|
30
37
|
current, previous = File.expand_path("..", current), current
|
31
38
|
end
|
32
39
|
|
@@ -57,5 +64,11 @@ module ParallelTests
|
|
57
64
|
Time.now
|
58
65
|
end
|
59
66
|
end
|
67
|
+
|
68
|
+
def delta
|
69
|
+
before = now.to_f
|
70
|
+
yield
|
71
|
+
now.to_f - before
|
72
|
+
end
|
60
73
|
end
|
61
74
|
end
|
data/lib/parallel_tests/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'tempfile'
|
3
3
|
require 'parallel_tests'
|
4
|
+
require 'shellwords'
|
4
5
|
|
5
6
|
module ParallelTests
|
6
7
|
class CLI
|
@@ -23,7 +24,7 @@ module ParallelTests
|
|
23
24
|
Tempfile.open 'parallel_tests-lock' do |lock|
|
24
25
|
return Parallel.map(items, :in_threads => num_processes) do |item|
|
25
26
|
result = yield(item)
|
26
|
-
|
27
|
+
reprint_output(result, lock.path) if options[:serialize_stdout]
|
27
28
|
result
|
28
29
|
end
|
29
30
|
end
|
@@ -34,10 +35,20 @@ module ParallelTests
|
|
34
35
|
|
35
36
|
report_time_taken do
|
36
37
|
groups = @runner.tests_in_groups(options[:files], num_processes, options)
|
37
|
-
|
38
|
+
groups.reject! &:empty?
|
38
39
|
|
39
|
-
test_results =
|
40
|
-
|
40
|
+
test_results = if options[:only_group]
|
41
|
+
groups_to_run = options[:only_group].collect{|i| groups[i - 1]}.compact
|
42
|
+
report_number_of_tests(groups_to_run)
|
43
|
+
execute_in_parallel(groups_to_run, groups_to_run.size, options) do |group|
|
44
|
+
run_tests(group, groups_to_run.index(group), 1, options)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
report_number_of_tests(groups)
|
48
|
+
|
49
|
+
execute_in_parallel(groups, groups.size, options) do |group|
|
50
|
+
run_tests(group, groups.index(group), num_processes, options)
|
51
|
+
end
|
41
52
|
end
|
42
53
|
|
43
54
|
report_results(test_results)
|
@@ -54,12 +65,23 @@ module ParallelTests
|
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
57
|
-
def
|
58
|
-
lock
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
68
|
+
def reprint_output(result, lockfile)
|
69
|
+
lock(lockfile) do
|
70
|
+
$stdout.puts result[:stdout]
|
71
|
+
$stdout.flush
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def lock(lockfile)
|
76
|
+
File.open(lockfile) do |lock|
|
77
|
+
begin
|
78
|
+
lock.flock File::LOCK_EX
|
79
|
+
yield
|
80
|
+
ensure
|
81
|
+
# This shouldn't be necessary, but appears to be
|
82
|
+
lock.flock File::LOCK_UN
|
83
|
+
end
|
84
|
+
end
|
63
85
|
end
|
64
86
|
|
65
87
|
def report_results(test_results)
|
@@ -71,8 +93,9 @@ module ParallelTests
|
|
71
93
|
def report_number_of_tests(groups)
|
72
94
|
name = @runner.test_file_name
|
73
95
|
num_processes = groups.size
|
74
|
-
num_tests = groups.map(&:size).inject(:+)
|
75
|
-
|
96
|
+
num_tests = groups.map(&:size).inject(0, :+)
|
97
|
+
tests_per_process = (num_processes == 0 ? 0 : num_tests / num_processes)
|
98
|
+
puts "#{num_processes} processes for #{num_tests} #{name}s, ~ #{tests_per_process} #{name}s per process"
|
76
99
|
end
|
77
100
|
|
78
101
|
#exit with correct status code so rake parallel:test && echo 123 works
|
@@ -83,23 +106,29 @@ module ParallelTests
|
|
83
106
|
def parse_options!(argv)
|
84
107
|
options = {}
|
85
108
|
OptionParser.new do |opts|
|
86
|
-
opts.banner =
|
87
|
-
Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
|
109
|
+
opts.banner = <<-BANNER.gsub(/^ /, '')
|
110
|
+
Run all tests in parallel, giving each process ENV['TEST_ENV_NUMBER'] ('', '2', '3', ...)
|
111
|
+
|
112
|
+
[optional] Only selected files & folders:
|
113
|
+
parallel_test test/bar test/baz/xxx_text.rb
|
88
114
|
|
89
|
-
[optional]
|
90
|
-
|
115
|
+
[optional] Pass test-options and files via `--`:
|
116
|
+
parallel_test -- -t acceptance -f progress -- spec/foo_spec.rb spec/acceptance
|
91
117
|
|
92
|
-
Options are:
|
93
|
-
BANNER
|
118
|
+
Options are:
|
119
|
+
BANNER
|
94
120
|
opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
|
95
121
|
opts.on("-p", "--pattern [PATTERN]", "run tests matching this pattern") { |pattern| options[:pattern] = /#{pattern}/ }
|
96
|
-
opts.on("--group-by [TYPE]", <<-TEXT
|
97
|
-
group tests by:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
122
|
+
opts.on("--group-by [TYPE]", <<-TEXT.gsub(/^ /, '')
|
123
|
+
group tests by:
|
124
|
+
found - order of finding files
|
125
|
+
steps - number of cucumber/spinach steps
|
126
|
+
scenarios - individual cucumber scenarios
|
127
|
+
filesize - by size of the file
|
128
|
+
runtime - info from runtime log
|
129
|
+
default - runtime when runtime log is filled otherwise filesize
|
130
|
+
TEXT
|
131
|
+
) { |type| options[:group_by] = type.to_sym }
|
103
132
|
opts.on("-m [FLOAT]", "--multiply-processes [FLOAT]", Float, "use given number as a multiplier of processes to run") { |multiply| options[:multiply] = multiply }
|
104
133
|
|
105
134
|
opts.on("-s [PATTERN]", "--single [PATTERN]",
|
@@ -115,9 +144,11 @@ TEXT
|
|
115
144
|
options[:isolate] = true
|
116
145
|
end
|
117
146
|
|
118
|
-
opts.on("-
|
119
|
-
|
120
|
-
opts.on("-
|
147
|
+
opts.on("--only-group INT[, INT]", Array) { |groups| options[:only_group] = groups.map(&:to_i) }
|
148
|
+
|
149
|
+
opts.on("-e", "--exec [COMMAND]", "execute this code parallel and with ENV['TEST_ENV_NUMBER']") { |path| options[:execute] = path }
|
150
|
+
opts.on("-o", "--test-options '[OPTIONS]'", "execute test commands with those options") { |arg| options[:test_options] = arg.lstrip }
|
151
|
+
opts.on("-t", "--type [TYPE]", "test(default) / rspec / cucumber / spinach") do |type|
|
121
152
|
begin
|
122
153
|
@runner = load_runner(type)
|
123
154
|
rescue NameError, LoadError => e
|
@@ -125,30 +156,73 @@ TEXT
|
|
125
156
|
abort
|
126
157
|
end
|
127
158
|
end
|
159
|
+
opts.on("--suffix [PATTERN]", <<-TEXT.gsub(/^ /, '')
|
160
|
+
override built in test file pattern (should match suffix):
|
161
|
+
'_spec\.rb$' - matches rspec files
|
162
|
+
'_(test|spec).rb$' - matches test or spec files
|
163
|
+
TEXT
|
164
|
+
) { |pattern| options[:suffix] = /#{pattern}/ }
|
128
165
|
opts.on("--serialize-stdout", "Serialize stdout output, nothing will be written until everything is done") { options[:serialize_stdout] = true }
|
166
|
+
opts.on("--combine-stderr", "Combine stderr into stdout, useful in conjunction with --serialize-stdout") { options[:combine_stderr] = true }
|
129
167
|
opts.on("--non-parallel", "execute same commands but do not in parallel, needs --exec") { options[:non_parallel] = true }
|
130
168
|
opts.on("--no-symlinks", "Do not traverse symbolic links to find test files") { options[:symlinks] = false }
|
131
169
|
opts.on("--advance-number [NUMBER]", Integer, "Advance test env number by specified number") { |n| options[:advance_number] = n }
|
132
170
|
opts.on('--ignore-tags [PATTERN]', 'When counting steps ignore scenarios with tags that match this pattern') { |arg| options[:ignore_tag_pattern] = arg }
|
133
171
|
opts.on("--nice", "execute test commands with low priority.") { options[:nice] = true }
|
172
|
+
opts.on("--runtime-log [PATH]", "Location of previously recorded test runtimes") { |path| options[:runtime_log] = path }
|
173
|
+
opts.on("--unknown-runtime [FLOAT]", "Use given number as unknown runtime (otherwise use average time)") { |time| options[:unknown_runtime] = time.to_f }
|
174
|
+
opts.on("--verbose", "Print more output") { options[:verbose] = true }
|
134
175
|
opts.on("-v", "--version", "Show Version") { puts ParallelTests::VERSION; exit }
|
135
176
|
opts.on("-h", "--help", "Show this.") { puts opts; exit }
|
136
177
|
end.parse!(argv)
|
137
178
|
|
138
|
-
raise "--group-by found and --single-process are not supported" if options[:group_by] == :found and options[:single_process]
|
139
|
-
|
140
179
|
if options[:count] == 0
|
141
180
|
options.delete(:count)
|
142
181
|
options[:non_parallel] = true
|
143
182
|
end
|
144
183
|
|
145
|
-
|
184
|
+
files, remaining = extract_file_paths(argv)
|
185
|
+
unless options[:execute]
|
186
|
+
abort "Pass files or folders to run" unless files.any?
|
187
|
+
options[:files] = files
|
188
|
+
end
|
189
|
+
|
190
|
+
append_test_options(options, remaining)
|
191
|
+
|
192
|
+
options[:group_by] ||= :filesize if options[:only_group]
|
193
|
+
|
194
|
+
raise "--group-by found and --single-process are not supported" if options[:group_by] == :found and options[:single_process]
|
195
|
+
allowed = [:filesize, :runtime, :found]
|
196
|
+
if !allowed.include?(options[:group_by]) && options[:only_group]
|
197
|
+
raise "--group-by #{allowed.join(" or ")} is required for --only-group"
|
198
|
+
end
|
199
|
+
|
146
200
|
options
|
147
201
|
end
|
148
202
|
|
203
|
+
def extract_file_paths(argv)
|
204
|
+
dash_index = argv.rindex("--")
|
205
|
+
file_args_at = (dash_index || -1) + 1
|
206
|
+
[argv[file_args_at..-1], argv[0...(dash_index || 0)]]
|
207
|
+
end
|
208
|
+
|
209
|
+
def extract_test_options(argv)
|
210
|
+
dash_index = argv.index("--") || -1
|
211
|
+
argv[dash_index+1..-1]
|
212
|
+
end
|
213
|
+
|
214
|
+
def append_test_options(options, argv)
|
215
|
+
new_opts = extract_test_options(argv)
|
216
|
+
return if new_opts.empty?
|
217
|
+
|
218
|
+
prev_and_new = [options[:test_options], new_opts.shelljoin]
|
219
|
+
options[:test_options] = prev_and_new.compact.join(' ')
|
220
|
+
end
|
221
|
+
|
149
222
|
def load_runner(type)
|
150
223
|
require "parallel_tests/#{type}/runner"
|
151
|
-
|
224
|
+
runner_classname = type.split("_").map(&:capitalize).join.sub("Rspec", "RSpec")
|
225
|
+
klass_name = "ParallelTests::#{runner_classname}::Runner"
|
152
226
|
klass_name.split('::').inject(Object) { |x, y| x.const_get(y) }
|
153
227
|
end
|
154
228
|
|
@@ -168,9 +242,15 @@ TEXT
|
|
168
242
|
end
|
169
243
|
|
170
244
|
def report_time_taken
|
171
|
-
|
172
|
-
|
173
|
-
|
245
|
+
seconds = ParallelTests.delta { yield }.to_i
|
246
|
+
puts "\nTook #{seconds} seconds#{detailed_duration(seconds)}"
|
247
|
+
end
|
248
|
+
|
249
|
+
def detailed_duration(seconds)
|
250
|
+
parts = [ seconds / 3600, seconds % 3600 / 60, seconds % 60 ].drop_while(&:zero?)
|
251
|
+
return if parts.size < 2
|
252
|
+
parts = parts.map { |i| "%02d" % i }.join(':').sub(/^0/, '')
|
253
|
+
" (#{parts})"
|
174
254
|
end
|
175
255
|
|
176
256
|
def final_fail_message
|