parallel_rspec 0.3.1 → 2.0.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 +5 -5
- data/README.md +38 -3
- data/lib/parallel_rspec/client.rb +14 -0
- data/lib/parallel_rspec/config.rb +13 -0
- data/lib/parallel_rspec/example.rb +4 -2
- data/lib/parallel_rspec/railtie.rb +9 -6
- data/lib/parallel_rspec/rake_task.rb +10 -0
- data/lib/parallel_rspec/runner.rb +14 -8
- data/lib/parallel_rspec/server.rb +26 -8
- data/lib/parallel_rspec/tasks.rake +10 -2
- data/lib/parallel_rspec/version.rb +1 -1
- data/lib/parallel_rspec/workers.rb +19 -4
- data/lib/parallel_rspec.rb +12 -0
- data/parallel_rspec.gemspec +2 -2
- metadata +20 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 83c17d292ba1b11cd79f83f1d8b795d0e7a606fe605ab998fb8e71d6876212fe
|
4
|
+
data.tar.gz: e6504610a0782653c34ac985fa355588f3fe75880c41cfda63c637b5520c155f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50a9c698147a7d65ff0452d3c83898dc46a54173683b9fa0886fc9b50aea9daae6205664063ccaee63a936cab567e2e26a3a6ff7fdf2dbcd2e2304c06da4e697
|
7
|
+
data.tar.gz: a16b420371af5586f1ff8f86d398cf46344c6b292430e853c82ac349f53f28d42882eff736f416168a4fdaabf6ffe62d971bdca61410ff81ae2b363a7bc04081
|
data/README.md
CHANGED
@@ -24,17 +24,17 @@ And then execute:
|
|
24
24
|
|
25
25
|
$ bundle
|
26
26
|
|
27
|
-
This version of ParallelRSpec has been tested with RSpec 3.
|
27
|
+
This version of ParallelRSpec has been tested with RSpec 3.10.
|
28
28
|
|
29
29
|
## Usage
|
30
30
|
|
31
31
|
By default, ParallelRSpec will use two workers. If you would like to use more, set an environment variable:
|
32
32
|
|
33
|
-
$ export WORKERS=
|
33
|
+
$ export WORKERS=4
|
34
34
|
|
35
35
|
ParallelRSpec runs each worker with its own copy of the test database to avoid locking and deadlocking problems. To create these and populate them with your schema, run:
|
36
36
|
|
37
|
-
$ bundle exec db:parallel:create db:parallel:prepare
|
37
|
+
$ bundle exec rake db:parallel:create db:parallel:prepare
|
38
38
|
|
39
39
|
ParallelRSpec will automatically make the database name for each worker based on the name you used for the `test` environment in `config/database.yml`. For example, if your normal `test` database is `foo_test`, worker 1 will keep using `foo_test` but worker 2's database will be `foo_test2`.
|
40
40
|
|
@@ -53,11 +53,46 @@ You may like to make an alias:
|
|
53
53
|
|
54
54
|
When you change WORKERS, don't forget to restart Spring and re-run the create and populate steps above if necessary.
|
55
55
|
|
56
|
+
To set up a rake task which uses parallel_rspec, use, for example:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
require 'parallel_rspec'
|
60
|
+
|
61
|
+
ParallelRSpec::RakeTask.new(:prspec) do |t|
|
62
|
+
ENV['WORKERS'] = '4'
|
63
|
+
t.pattern = "**/spec/*_spec.rb"
|
64
|
+
t.rspec_opts = "--tag parallel"
|
65
|
+
# etc...
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
If you'd like code to run after parallel_rspec has created each worker, you can specify a block to run:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
ParallelRSpec.configure do |config|
|
73
|
+
config.after_fork do |worker_number|
|
74
|
+
puts "I am worker #{worker_number}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
You might also want to detect whether your spec suite is running under ParallelRSpec or not:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
do_something unless ParallelRSpec.running?
|
83
|
+
```
|
84
|
+
|
56
85
|
## Contributing
|
57
86
|
|
58
87
|
Bug reports and pull requests are welcome on GitHub at https://github.com/willbryant/parallel_rspec.
|
59
88
|
|
60
89
|
|
90
|
+
## Thanks
|
91
|
+
|
92
|
+
* Charles Horn (@hornc)
|
93
|
+
* Roger Nesbitt (@mogest)
|
94
|
+
|
95
|
+
|
61
96
|
## License
|
62
97
|
|
63
98
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -26,6 +26,10 @@ module ParallelRSpec
|
|
26
26
|
channel_to_server.write([:example_failed, serialize_example(example)])
|
27
27
|
end
|
28
28
|
|
29
|
+
def example_finished(example)
|
30
|
+
channel_to_server.write([:example_finished, serialize_example(example)])
|
31
|
+
end
|
32
|
+
|
29
33
|
def example_pending(example)
|
30
34
|
channel_to_server.write([:example_pending, serialize_example(example)])
|
31
35
|
end
|
@@ -40,6 +44,7 @@ module ParallelRSpec
|
|
40
44
|
example.description,
|
41
45
|
example.exception,
|
42
46
|
example.location_rerun_argument,
|
47
|
+
ExampleGroup.new([]),
|
43
48
|
example.metadata.slice(
|
44
49
|
:absolute_file_path,
|
45
50
|
:described_class,
|
@@ -57,5 +62,14 @@ module ParallelRSpec
|
|
57
62
|
:shared_group_inclusion_backtrace,
|
58
63
|
:type))
|
59
64
|
end
|
65
|
+
|
66
|
+
def next_example_to_run
|
67
|
+
channel_to_server.write([:next_example_to_run])
|
68
|
+
channel_to_server.read
|
69
|
+
end
|
70
|
+
|
71
|
+
def result(success)
|
72
|
+
channel_to_server.write([:result, success])
|
73
|
+
end
|
60
74
|
end
|
61
75
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module ParallelRSpec
|
2
|
+
ExampleGroup = Struct.new(:parent_groups)
|
3
|
+
|
2
4
|
# only the good bits of RSpec's Example class, those needed by the reporters and formatters and
|
3
5
|
# marshallable.
|
4
|
-
Example = Struct.new(:id, :description, :exception, :location_rerun_argument, :metadata) do
|
6
|
+
Example = Struct.new(:id, :description, :exception, :location_rerun_argument, :example_group, :metadata) do
|
5
7
|
def self.delegate_to_metadata(key)
|
6
8
|
define_method(key) { metadata[key] }
|
7
9
|
end
|
@@ -13,4 +15,4 @@ module ParallelRSpec
|
|
13
15
|
delegate_to_metadata :pending
|
14
16
|
delegate_to_metadata :skip
|
15
17
|
end
|
16
|
-
end
|
18
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'rails'
|
2
3
|
|
3
|
-
module ParallelRSpec
|
4
|
-
|
5
|
-
|
4
|
+
module ParallelRSpec
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
railtie_name :parallel_rspec
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
rake_tasks do
|
9
|
+
load "parallel_rspec/tasks.rake"
|
10
|
+
end
|
9
11
|
end
|
10
12
|
end
|
13
|
+
rescue LoadError
|
11
14
|
end
|
@@ -16,6 +16,12 @@ end
|
|
16
16
|
|
17
17
|
module ParallelRSpec
|
18
18
|
class Runner < RSpec::Core::Runner
|
19
|
+
@@running = false
|
20
|
+
|
21
|
+
def self.running?
|
22
|
+
@@running
|
23
|
+
end
|
24
|
+
|
19
25
|
# Runs the suite of specs and exits the process with an appropriate exit
|
20
26
|
# code.
|
21
27
|
def self.invoke
|
@@ -39,6 +45,7 @@ module ParallelRSpec
|
|
39
45
|
# or the configured failure exit code (1 by default) if specs
|
40
46
|
# failed.
|
41
47
|
def self.run(args, err=$stderr, out=$stdout)
|
48
|
+
@@running = true
|
42
49
|
RSpec::Core::Runner.trap_interrupt
|
43
50
|
options = RSpec::Core::ConfigurationOptions.new(args)
|
44
51
|
new(options).run(err, out)
|
@@ -66,15 +73,14 @@ module ParallelRSpec
|
|
66
73
|
workers = Workers.new
|
67
74
|
workers.run_test_workers_with_server(server) do |worker, channel_to_server|
|
68
75
|
client = Client.new(channel_to_server)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
success = true
|
77
|
+
while next_example = client.next_example_to_run
|
78
|
+
example_group, example_index = *next_example
|
79
|
+
example = RSpec.world.filtered_examples[example_group][example_index]
|
80
|
+
example_group_instance = example_group.new(example.inspect_output)
|
81
|
+
success = example.run(example_group_instance, client) && success
|
75
82
|
end
|
76
|
-
|
77
|
-
channel_to_server.write([:result, success])
|
83
|
+
client.result(success)
|
78
84
|
end
|
79
85
|
server.success?
|
80
86
|
end
|
@@ -1,34 +1,52 @@
|
|
1
1
|
module ParallelRSpec
|
2
2
|
class Server
|
3
|
-
attr_reader :reporter
|
3
|
+
attr_reader :remaining_example_group_indexes, :reporter
|
4
4
|
|
5
5
|
def initialize(reporter)
|
6
|
+
@remaining_example_group_indexes = RSpec.world.filtered_examples.each_with_object({}) do |(example_group, examples), results|
|
7
|
+
results[example_group] = examples.size unless example_group.any_context_hooks? || examples.size.zero?
|
8
|
+
end
|
6
9
|
@reporter = reporter
|
7
10
|
@success = true
|
8
11
|
end
|
9
12
|
|
10
|
-
def example_started(example)
|
13
|
+
def example_started(example, channel_to_client)
|
11
14
|
reporter.example_started(example)
|
12
15
|
end
|
13
16
|
|
14
|
-
def example_passed(example)
|
17
|
+
def example_passed(example, channel_to_client)
|
15
18
|
reporter.example_passed(example)
|
16
19
|
end
|
17
20
|
|
18
|
-
def example_failed(example)
|
21
|
+
def example_failed(example, channel_to_client)
|
19
22
|
reporter.example_failed(example)
|
20
23
|
end
|
21
24
|
|
22
|
-
def
|
25
|
+
def example_finished(example, channel_to_client)
|
26
|
+
reporter.example_finished(example)
|
27
|
+
end
|
28
|
+
|
29
|
+
def example_pending(example, channel_to_client)
|
23
30
|
reporter.example_pending(example)
|
24
31
|
end
|
25
32
|
|
26
|
-
def deprecation(hash)
|
33
|
+
def deprecation(hash, channel_to_client)
|
27
34
|
reporter.deprecation(hash)
|
28
35
|
end
|
29
36
|
|
30
|
-
def
|
31
|
-
|
37
|
+
def next_example_to_run(channel_to_client)
|
38
|
+
if remaining_example_group_indexes.empty?
|
39
|
+
channel_to_client.write(nil)
|
40
|
+
else
|
41
|
+
klass = remaining_example_group_indexes.keys.first
|
42
|
+
remaining_example_group_indexes[klass] -= 1
|
43
|
+
channel_to_client.write([klass, remaining_example_group_indexes[klass]])
|
44
|
+
remaining_example_group_indexes.delete(klass) if remaining_example_group_indexes[klass].zero?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def result(success, channel_to_client)
|
49
|
+
@success &&= success
|
32
50
|
end
|
33
51
|
|
34
52
|
def success?
|
@@ -22,7 +22,11 @@ db_namespace = namespace :db do
|
|
22
22
|
begin
|
23
23
|
ParallelRSpec::Workers.new.run_test_workers do |worker|
|
24
24
|
ActiveRecord::Schema.verbose = false
|
25
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
25
|
+
if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:load_schema_current)
|
26
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current :ruby, ENV['SCHEMA'], 'test'
|
27
|
+
else
|
28
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
|
29
|
+
end
|
26
30
|
end
|
27
31
|
ensure
|
28
32
|
if should_reconnect
|
@@ -34,7 +38,11 @@ db_namespace = namespace :db do
|
|
34
38
|
# desc "Recreate the test database from an existent structure.sql file"
|
35
39
|
task :load_structure => %w(db:parallel:purge) do
|
36
40
|
ParallelRSpec::Workers.new.run_test_workers do |worker|
|
37
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
41
|
+
if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:load_schema_current)
|
42
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current :sql, ENV['SCHEMA'], 'test'
|
43
|
+
else
|
44
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
@@ -2,7 +2,7 @@ module ParallelRSpec
|
|
2
2
|
class Workers
|
3
3
|
def self.number_of_workers
|
4
4
|
workers = ENV['WORKERS'].to_i
|
5
|
-
workers =
|
5
|
+
workers = 2 if workers.zero?
|
6
6
|
workers
|
7
7
|
end
|
8
8
|
|
@@ -30,6 +30,11 @@ module ParallelRSpec
|
|
30
30
|
pid = fork do
|
31
31
|
channel_to_client.close
|
32
32
|
establish_test_database_connection(worker)
|
33
|
+
|
34
|
+
Config.after_fork.each do |proc|
|
35
|
+
proc.call(worker)
|
36
|
+
end
|
37
|
+
|
33
38
|
yield worker, channel_to_server
|
34
39
|
end
|
35
40
|
|
@@ -46,7 +51,7 @@ module ParallelRSpec
|
|
46
51
|
while !channels.empty?
|
47
52
|
Channel.read_select(channels).each do |channel|
|
48
53
|
if command = channel.read
|
49
|
-
server.send(*command)
|
54
|
+
server.send(*(command + [channel]))
|
50
55
|
else
|
51
56
|
channels.delete(channel)
|
52
57
|
end
|
@@ -56,8 +61,18 @@ module ParallelRSpec
|
|
56
61
|
|
57
62
|
def establish_test_database_connection(worker)
|
58
63
|
ENV['TEST_ENV_NUMBER'] = worker.to_s
|
59
|
-
ActiveRecord
|
60
|
-
|
64
|
+
if defined?(ActiveRecord)
|
65
|
+
if ActiveRecord::Base.configurations.respond_to?(:configs_for)
|
66
|
+
ActiveRecord::Base.configurations.configs_for(env_name: 'test').each do |configuration|
|
67
|
+
configuration.database << worker.to_s unless worker == 1
|
68
|
+
ActiveRecord::Base.establish_connection(configuration)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
configuration = ActiveRecord::Base.configurations['test']
|
72
|
+
configuration.with_indifferent_access['database'] << worker.to_s unless worker == 1
|
73
|
+
ActiveRecord::Base.establish_connection(configuration)
|
74
|
+
end
|
75
|
+
end
|
61
76
|
end
|
62
77
|
|
63
78
|
def verify_children(child_pids)
|
data/lib/parallel_rspec.rb
CHANGED
@@ -1,8 +1,20 @@
|
|
1
1
|
require "parallel_rspec/version"
|
2
|
+
require "parallel_rspec/config"
|
2
3
|
require "parallel_rspec/channel"
|
3
4
|
require "parallel_rspec/workers"
|
4
5
|
require "parallel_rspec/example"
|
5
6
|
require "parallel_rspec/server"
|
6
7
|
require "parallel_rspec/client"
|
8
|
+
require "parallel_rspec/rake_task"
|
7
9
|
require "parallel_rspec/runner"
|
8
10
|
require "parallel_rspec/railtie"
|
11
|
+
|
12
|
+
module ParallelRSpec
|
13
|
+
def self.configure
|
14
|
+
yield Config
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.running?
|
18
|
+
Runner.running?
|
19
|
+
end
|
20
|
+
end
|
data/parallel_rspec.gemspec
CHANGED
@@ -19,6 +19,6 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.
|
23
|
-
spec.
|
22
|
+
spec.add_dependency "rake", "> 10.0"
|
23
|
+
spec.add_dependency "rspec"
|
24
24
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Bryant, Powershop New Zealand Ltd
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
19
|
+
version: '10.0'
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '10.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
type: :
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
description: This gem lets you run your RSpec examples in parallel across across your
|
42
42
|
CPUs. Each worker automatically gets its own database to avoid conflicts. The
|
43
43
|
optional spring-prspec gem adds support for running under Spring.
|
@@ -58,8 +58,10 @@ files:
|
|
58
58
|
- lib/parallel_rspec.rb
|
59
59
|
- lib/parallel_rspec/channel.rb
|
60
60
|
- lib/parallel_rspec/client.rb
|
61
|
+
- lib/parallel_rspec/config.rb
|
61
62
|
- lib/parallel_rspec/example.rb
|
62
63
|
- lib/parallel_rspec/railtie.rb
|
64
|
+
- lib/parallel_rspec/rake_task.rb
|
63
65
|
- lib/parallel_rspec/runner.rb
|
64
66
|
- lib/parallel_rspec/server.rb
|
65
67
|
- lib/parallel_rspec/tasks.rake
|
@@ -70,7 +72,7 @@ homepage: https://github.com/willbryant/parallel_rspec
|
|
70
72
|
licenses:
|
71
73
|
- MIT
|
72
74
|
metadata: {}
|
73
|
-
post_install_message:
|
75
|
+
post_install_message:
|
74
76
|
rdoc_options: []
|
75
77
|
require_paths:
|
76
78
|
- lib
|
@@ -85,9 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
87
|
- !ruby/object:Gem::Version
|
86
88
|
version: '0'
|
87
89
|
requirements: []
|
88
|
-
|
89
|
-
|
90
|
-
signing_key:
|
90
|
+
rubygems_version: 3.0.3
|
91
|
+
signing_key:
|
91
92
|
specification_version: 4
|
92
93
|
summary: This gem lets you run your RSpec examples in parallel across across your
|
93
94
|
CPUs.
|