parallel_rspec 0.3.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cd859eb40b317c48862eb67b4f24f3fa50e4bea8
4
- data.tar.gz: 6c04d37e7c0828a2b3bfa7112e9819a28b814c91
2
+ SHA256:
3
+ metadata.gz: 83c17d292ba1b11cd79f83f1d8b795d0e7a606fe605ab998fb8e71d6876212fe
4
+ data.tar.gz: e6504610a0782653c34ac985fa355588f3fe75880c41cfda63c637b5520c155f
5
5
  SHA512:
6
- metadata.gz: 10d65506bd40f980d529362af9b5e95e3da72d0be1eda7bdb86ec52f16ac903b38fb9a717c2ca63da7c2533e639b7a1368aa067a7623287af42337a4aa7ca076
7
- data.tar.gz: ef27474707581225d8514111a55c8859459979932730dade8872f62a70781dd4318ae51db90c33405aaac2674ffb067ef9fc71b39376030084824fd4dd514414
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.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=2
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
@@ -0,0 +1,13 @@
1
+ module ParallelRSpec
2
+ module Config
3
+ @after_fork = []
4
+
5
+ def self.after_fork(&block)
6
+ if block
7
+ @after_fork << block
8
+ else
9
+ @after_fork
10
+ end
11
+ end
12
+ end
13
+ 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
- require 'rails'
1
+ begin
2
+ require 'rails'
2
3
 
3
- module ParallelRSpec
4
- class Railtie < Rails::Railtie
5
- railtie_name :parallel_rspec
4
+ module ParallelRSpec
5
+ class Railtie < Rails::Railtie
6
+ railtie_name :parallel_rspec
6
7
 
7
- rake_tasks do
8
- load "parallel_rspec/tasks.rake"
8
+ rake_tasks do
9
+ load "parallel_rspec/tasks.rake"
10
+ end
9
11
  end
10
12
  end
13
+ rescue LoadError
11
14
  end
@@ -0,0 +1,10 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ module ParallelRSpec
4
+ class RakeTask < RSpec::Core::RakeTask
5
+ def initialize(*args, &task_block)
6
+ super
7
+ self.rspec_path = File.expand_path('../../../exe/prspec', __FILE__)
8
+ end
9
+ end
10
+ 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
- index = 0
70
- RSpec.world.filtered_examples.each do |group, examples|
71
- examples.reject! do |example|
72
- index += 1
73
- (index % workers.number_of_workers) != (worker % workers.number_of_workers)
74
- end
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
- success = example_groups.map { |g| g.run(client) }.all?
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 example_pending(example)
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 result(result)
31
- @success &&= result
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.load_schema_for ActiveRecord::Base.configurations['test'], :ruby, ENV['SCHEMA']
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.load_schema_for ActiveRecord::Base.configurations['test'], :sql, ENV['SCHEMA']
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
 
@@ -1,3 +1,3 @@
1
1
  module ParallelRSpec
2
- VERSION = "0.3.1"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -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 = 4 if workers.zero?
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::Base.configurations['test']['database'] << worker.to_s unless worker == 1
60
- ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
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)
@@ -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
@@ -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.add_development_dependency "bundler", "~> 1.10"
23
- spec.add_development_dependency "rake", "~> 10.0"
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.3.1
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: 2015-09-18 00:00:00.000000000 Z
11
+ date: 2021-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
20
- type: :development
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: '1.10'
26
+ version: '10.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
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: '10.0'
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
- rubyforge_project:
89
- rubygems_version: 2.2.2
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.