parallel_tests 1.1.1 → 1.2.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 +21 -22
- data/lib/parallel_tests.rb +7 -1
- data/lib/parallel_tests/cli.rb +2 -0
- data/lib/parallel_tests/gherkin/runner.rb +3 -3
- data/lib/parallel_tests/rspec/runner.rb +1 -1
- data/lib/parallel_tests/test/runtime_logger.rb +66 -56
- data/lib/parallel_tests/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3784fb4e94413d435daab2e99def28d2293562b
|
4
|
+
data.tar.gz: 65b533d73a5bfa04bdba27161c0d6baea8a202f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab5162168063cfba147586acf5219c7065edfdf3bb110cda69c952165a3dad045464cac76c4e4c04839afa1dcaa9e23fbbbd0a5f650027788db4b6ed7aae150e
|
7
|
+
data.tar.gz: 0cc7aedcc2978f92ef01a9c81d2d0807665cc8db6b1134d40ecaa4d078b7ca8722a9b0a26c7ae4625b4f07d57bf153234eec55a6e4ed390f232ed04906f65266
|
data/Readme.md
CHANGED
@@ -1,24 +1,19 @@
|
|
1
|
-
Speedup Test::Unit + RSpec + Cucumber by running parallel on multiple
|
2
|
-
ParallelTests splits tests into even groups(by number of
|
3
|
-
|
4
|
-
[upgrading from 0.6 ?](https://github.com/grosser/parallel_tests/wiki/Upgrading-0.6.x-to-0.7.x)
|
1
|
+
Speedup Test::Unit + RSpec + Cucumber + Spinach by running parallel on multiple CPU cores.<br/>
|
2
|
+
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
3
|
|
6
4
|
Setup for Rails
|
7
5
|
===============
|
8
6
|
[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
7
|
|
11
8
|
### Install
|
12
|
-
If you use RSpec: ensure you have >= 2.4
|
13
|
-
|
14
|
-
As gem
|
15
9
|
|
16
10
|
```ruby
|
17
|
-
#
|
11
|
+
# Gemfile
|
18
12
|
gem "parallel_tests", :group => :development
|
19
13
|
```
|
20
14
|
|
21
15
|
### Add to `config/database.yml`
|
16
|
+
|
22
17
|
ParallelTests uses 1 database per test-process.
|
23
18
|
<table>
|
24
19
|
<tr><td>Process number</td><td>1</td><td>2</td><td>3</td></tr>
|
@@ -93,6 +88,8 @@ Loggers
|
|
93
88
|
Even test group run-times
|
94
89
|
-------------------------
|
95
90
|
|
91
|
+
### RSpec
|
92
|
+
|
96
93
|
Add the `RuntimeLogger` to log how long each test takes to run.
|
97
94
|
This log file will be loaded on the next test run, and the tests will be grouped
|
98
95
|
so that each process should finish around the same time.
|
@@ -102,15 +99,19 @@ Rspec: Add to your `.rspec_parallel` (or `.rspec`) :
|
|
102
99
|
--format progress
|
103
100
|
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
|
104
101
|
|
105
|
-
Test::Unit
|
102
|
+
### Test::Unit & Minitest 4
|
103
|
+
|
104
|
+
Add to your `test_helper.rb`:
|
106
105
|
```ruby
|
107
106
|
require 'parallel_tests/test/runtime_logger'
|
108
107
|
```
|
109
108
|
|
109
|
+
results will be logged to tmp/parallel_runtime_test.log
|
110
|
+
|
110
111
|
RSpec: SummaryLogger
|
111
112
|
--------------------
|
112
113
|
|
113
|
-
|
114
|
+
Log the test output without the different processes overwriting each other.
|
114
115
|
|
115
116
|
Add the following to your `.rspec_parallel` (or `.rspec`) :
|
116
117
|
|
@@ -120,7 +121,7 @@ Add the following to your `.rspec_parallel` (or `.rspec`) :
|
|
120
121
|
RSpec: FailuresLogger
|
121
122
|
-----------------------
|
122
123
|
|
123
|
-
|
124
|
+
Produce pasteable command-line snippets for each failed example.
|
124
125
|
|
125
126
|
E.g.
|
126
127
|
|
@@ -134,7 +135,7 @@ Add the following to your `.rspec_parallel` (or `.rspec`) :
|
|
134
135
|
Cucumber: FailuresLogger
|
135
136
|
-----------------------
|
136
137
|
|
137
|
-
|
138
|
+
Log failed cucumber scenarios to the specified file. The filename can be passed to cucumber, prefixed with '@' to rerun failures.
|
138
139
|
|
139
140
|
Usage:
|
140
141
|
|
@@ -148,10 +149,11 @@ Note if your `cucumber.yml` default profile uses `<%= std_opts %>` you may need
|
|
148
149
|
|
149
150
|
To rerun failures:
|
150
151
|
|
151
|
-
|
152
|
+
cucumber @tmp/cucumber_failures.log
|
152
153
|
|
153
154
|
Setup for non-rails
|
154
155
|
===================
|
156
|
+
|
155
157
|
gem install parallel_tests
|
156
158
|
# go to your project dir
|
157
159
|
parallel_test test/
|
@@ -210,13 +212,10 @@ You can run any kind of code in parallel with -e / --execute
|
|
210
212
|
TIPS
|
211
213
|
====
|
212
214
|
- [RSpec] add a `.rspec_parallel` to use different options, e.g. **no --drb**
|
213
|
-
-
|
214
|
-
- [
|
215
|
-
- [RSpec] remove --loadby from you spec/*.opts
|
215
|
+
- Spring does not work with parallel_tests, use `DISABLE_SPRING=1 rake parallel:spec` if you have spring hardcoded in your binaries
|
216
|
+
- [RSpec] remove `--loadby` from `.rspec`
|
216
217
|
- [RSpec] Instantly see failures (instead of just a red F) with [rspec-instafail](https://github.com/grosser/rspec-instafail)
|
217
|
-
- [Bundler] if you have a `Gemfile` then `bundle exec` will be used to run tests
|
218
218
|
- [Cucumber] add a `parallel: foo` profile to your `config/cucumber.yml` and it will be used to run parallel tests
|
219
|
-
- [Cucumber] Pass in cucumber options by not giving the options an identifier ex: `rake parallel:features[,,'cucumber_opts']`
|
220
219
|
- [Capybara setup](https://github.com/grosser/parallel_tests/wiki)
|
221
220
|
- [Sphinx setup](https://github.com/grosser/parallel_tests/wiki)
|
222
221
|
- [Capistrano setup](https://github.com/grosser/parallel_tests/wiki/Remotely-with-capistrano) let your tests run on a big box instead of your laptop
|
@@ -224,13 +223,13 @@ TIPS
|
|
224
223
|
- `export PARALLEL_TEST_PROCESSORS=X` in your environment and parallel_tests will use this number of processors by default
|
225
224
|
- [ZSH] use quotes to use rake arguments `rake "parallel:prepare[3]"`
|
226
225
|
- [email_spec and/or action_mailer_cache_delivery](https://github.com/grosser/parallel_tests/wiki)
|
227
|
-
- [Memcached] use different namespaces e.g. `config.cache_store = ..., :
|
226
|
+
- [Memcached] use different namespaces e.g. `config.cache_store = ..., namespace: "test_#{ENV['TEST_ENV_NUMBER']}"`
|
228
227
|
- [zeus-parallel_tests](https://github.com/sevos/zeus-parallel_tests)
|
229
228
|
- [Distributed parallel test (e.g. Travis Support)](https://github.com/grosser/parallel_tests/wiki/Distributed-Parallel-Tests-and-Travis-Support)
|
229
|
+
- Contribute your own gotaches to the [Wiki](https://github.com/grosser/parallel_tests/wiki) or even better open a PR :)
|
230
230
|
|
231
231
|
TODO
|
232
232
|
====
|
233
|
-
- make tests consistently pass with `--order random` in .rspec
|
234
233
|
- fix tests vs cucumber >= 1.2 `unknown option --format`
|
235
234
|
- add integration tests for the rake tasks, maybe generate a rails project ...
|
236
235
|
- add unit tests for cucumber runtime formatter
|
@@ -240,7 +239,7 @@ Authors
|
|
240
239
|
====
|
241
240
|
inspired by [pivotal labs](http://pivotallabs.com/users/miked/blog/articles/849-parallelize-your-rspec-suite)
|
242
241
|
|
243
|
-
### [Contributors](
|
242
|
+
### [Contributors](https://github.com/grosser/parallel_tests/contributors)
|
244
243
|
- [Charles Finkel](http://charlesfinkel.com/)
|
245
244
|
- [Indrek Juhkam](http://urgas.eu)
|
246
245
|
- [Jason Morrison](http://jayunit.net)
|
data/lib/parallel_tests.rb
CHANGED
@@ -33,7 +33,7 @@ module ParallelTests
|
|
33
33
|
|
34
34
|
until !File.directory?(current) || current == previous
|
35
35
|
filename = File.join(current, "Gemfile")
|
36
|
-
return true if File.
|
36
|
+
return true if File.exist?(filename)
|
37
37
|
current, previous = File.expand_path("..", current), current
|
38
38
|
end
|
39
39
|
|
@@ -64,5 +64,11 @@ module ParallelTests
|
|
64
64
|
Time.now
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
def delta
|
69
|
+
before = now.to_f
|
70
|
+
yield
|
71
|
+
now.to_f - before
|
72
|
+
end
|
67
73
|
end
|
68
74
|
end
|
data/lib/parallel_tests/cli.rb
CHANGED
@@ -24,7 +24,7 @@ module ParallelTests
|
|
24
24
|
(runtime_logging if File.directory?(File.dirname(runtime_log))),
|
25
25
|
cucumber_opts(options[:test_options]),
|
26
26
|
*sanitized_test_files
|
27
|
-
].compact.join(' ')
|
27
|
+
].compact.reject(&:empty?).join(' ')
|
28
28
|
execute_command(cmd, process_number, num_processes, options)
|
29
29
|
end
|
30
30
|
|
@@ -90,7 +90,7 @@ module ParallelTests
|
|
90
90
|
|
91
91
|
|
92
92
|
def runtime_logging
|
93
|
-
"
|
93
|
+
"--format ParallelTests::Gherkin::RuntimeLogger --out #{runtime_log}"
|
94
94
|
end
|
95
95
|
|
96
96
|
def runtime_log
|
@@ -99,7 +99,7 @@ module ParallelTests
|
|
99
99
|
|
100
100
|
def determine_executable
|
101
101
|
case
|
102
|
-
when File.
|
102
|
+
when File.exist?("bin/#{name}")
|
103
103
|
"bin/#{name}"
|
104
104
|
when ParallelTests.bundler_enabled?
|
105
105
|
"bundle exec #{name}"
|
@@ -4,70 +4,59 @@ require 'parallel_tests/test/runner'
|
|
4
4
|
module ParallelTests
|
5
5
|
module Test
|
6
6
|
class RuntimeLogger
|
7
|
-
@@
|
7
|
+
@@prepared = false
|
8
8
|
|
9
9
|
class << self
|
10
|
-
def
|
11
|
-
|
10
|
+
def log_test_run(test)
|
11
|
+
prepare
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
13
|
+
result = nil
|
14
|
+
time = ParallelTests.delta { result = yield }
|
15
|
+
log(test, time)
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def unique_log
|
21
|
+
lock do
|
22
|
+
separator = "\n"
|
23
|
+
groups = File.read(logfile).split(separator).map { |line| line.split(":") }.group_by(&:first)
|
24
|
+
lines = groups.map { |file, times| "#{file}:#{times.map(&:last).map(&:to_f).inject(:+)}" }
|
25
|
+
File.write(logfile, lines.join(separator) + separator)
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
29
|
private
|
24
30
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
# ensure folder exists + clean out previous log
|
32
|
+
# this will happen in multiple processes, but should be roughly at the same time
|
33
|
+
# so there should be no log message lost
|
34
|
+
def prepare
|
35
|
+
return if @@prepared
|
36
|
+
@@prepared = true
|
37
|
+
FileUtils.mkdir_p(File.dirname(logfile))
|
38
|
+
File.write(logfile, '')
|
29
39
|
end
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if defined?(Rails)
|
37
|
-
result += case suspect.superclass.name
|
38
|
-
when "ActionDispatch::IntegrationTest"
|
39
|
-
"integration/"
|
40
|
-
when "ActionDispatch::PerformanceTest"
|
41
|
-
"performance/"
|
42
|
-
when "ActionController::TestCase"
|
43
|
-
"functional/"
|
44
|
-
when "ActionView::TestCase"
|
45
|
-
"unit/helpers/"
|
46
|
-
else
|
47
|
-
"unit/"
|
48
|
-
end
|
41
|
+
def log(test, time)
|
42
|
+
return unless message = message(test, time)
|
43
|
+
lock do
|
44
|
+
File.open(logfile, 'a') { |f| f.puts message }
|
49
45
|
end
|
50
|
-
result
|
51
46
|
end
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
59
|
-
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
60
|
-
word.gsub!(/\:\:/, '/')
|
61
|
-
word.tr!("-", "_")
|
62
|
-
word.downcase!
|
63
|
-
word
|
48
|
+
def message(test, time)
|
49
|
+
return unless method = test.public_instance_methods(true).detect { |method| method =~ /^test_/ }
|
50
|
+
delta = "%.2f" % time
|
51
|
+
filename = test.instance_method(method).source_location.first.sub("#{Dir.pwd}/", "")
|
52
|
+
"#{filename}:#{delta}"
|
64
53
|
end
|
65
54
|
|
66
|
-
def
|
67
|
-
File.open(
|
55
|
+
def lock
|
56
|
+
File.open(logfile, 'r') do |f|
|
68
57
|
begin
|
69
58
|
f.flock File::LOCK_EX
|
70
|
-
yield
|
59
|
+
yield
|
71
60
|
ensure
|
72
61
|
f.flock File::LOCK_UN
|
73
62
|
end
|
@@ -82,17 +71,38 @@ module ParallelTests
|
|
82
71
|
end
|
83
72
|
end
|
84
73
|
|
85
|
-
|
86
|
-
|
87
|
-
|
74
|
+
if defined?(MiniTest::Unit)
|
75
|
+
MiniTest::Unit.class_eval do
|
76
|
+
alias_method :_run_suite_without_runtime_log, :_run_suite
|
77
|
+
def _run_suite(*args)
|
78
|
+
ParallelTests::Test::RuntimeLogger.log_test_run(args.first) do
|
79
|
+
_run_suite_without_runtime_log(*args)
|
80
|
+
end
|
81
|
+
end
|
88
82
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
83
|
+
alias_method :_run_suites_without_runtime_log, :_run_suites
|
84
|
+
def _run_suites(*args)
|
85
|
+
result = _run_suites_without_runtime_log(*args)
|
86
|
+
ParallelTests::Test::RuntimeLogger.unique_log
|
87
|
+
result
|
88
|
+
end
|
95
89
|
end
|
90
|
+
else
|
91
|
+
require 'test/unit/testsuite'
|
92
|
+
class ::Test::Unit::TestSuite
|
93
|
+
alias_method :run_without_timing, :run
|
94
|
+
|
95
|
+
def run(result, &block)
|
96
|
+
test = tests.first
|
96
97
|
|
97
|
-
|
98
|
+
if test.is_a? ::Test::Unit::TestSuite # all tests ?
|
99
|
+
run_without_timing(result, &block)
|
100
|
+
ParallelTests::Test::RuntimeLogger.unique_log
|
101
|
+
else
|
102
|
+
ParallelTests::Test::RuntimeLogger.log_test_run(test.class) do
|
103
|
+
run_without_timing(result, &block)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
98
108
|
end
|
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: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parallel
|