rspec-parallel 2.14.8.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.
data/bin/rspec ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rspec/autorun'
5
+ rescue LoadError
6
+ $stderr.puts <<-EOS
7
+ #{'*'*50}
8
+ Could not find 'rspec/autorun'
9
+
10
+ This may happen if you're using rubygems as your package manager, but it is not
11
+ being required through some mechanism before executing the rspec command.
12
+
13
+ You may need to do one of the following in your shell:
14
+
15
+ # for bash/zsh
16
+ export RUBYOPT=rubygems
17
+
18
+ # for csh, etc.
19
+ set RUBYOPT=rubygems
20
+
21
+ For background, please see http://gist.github.com/54177.
22
+ #{'*'*50}
23
+ EOS
24
+ exit(1)
25
+ end
@@ -0,0 +1,2 @@
1
+ require 'rspec/core'
2
+ RSpec::Parallel::Runner.autorun
@@ -0,0 +1,44 @@
1
+ module RSpec
2
+ module Parallel
3
+ class CommandLine < RSpec::Core::CommandLine
4
+ def initialize(options, configuration=RSpec::configuration, world=RSpec::world)
5
+ if Array === options
6
+ options = ConfigurationOptions.new(options)
7
+ options.parse_options
8
+ end
9
+ @options = options
10
+ @configuration = configuration
11
+ @world = world
12
+ end
13
+
14
+ # Configures and runs a suite
15
+ #
16
+ # @param [IO] err
17
+ # @param [IO] out
18
+ def run_parallel(err, out)
19
+ @configuration.error_stream = err
20
+ @configuration.output_stream ||= out
21
+ @options.configure(@configuration)
22
+ @configuration.load_spec_files
23
+ @world.announce_filters
24
+
25
+ @configuration.reporter.report(@world.example_count, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
26
+ begin
27
+ @configuration.run_hook(:before, :suite)
28
+ group_threads = RSpec::Parallel::ExampleGroupThreadRunner.new(@configuration.thread_maximum)
29
+ @world.example_groups.ordered.map {|g| group_threads.run(g, reporter)}
30
+ group_threads.wait_for_completion
31
+
32
+ @world.example_groups.all? do |g|
33
+ result_for_this_group = g.filtered_examples.all? { |example| example.metadata[:execution_result].exception.nil? }
34
+ results_for_descendants = g.children.all? { |child| child.filtered_examples.all? { |example| example.metadata[:execution_result].exception.nil? } }
35
+ result_for_this_group && results_for_descendants
36
+ end ? 0 : @configuration.failure_exit_code
37
+ ensure
38
+ @configuration.run_hook(:after, :suite)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ module RSpec
2
+ module Parallel
3
+ class Configuration < RSpec::Core::Configuration
4
+ attr_accessor :thread_maximum
5
+
6
+ def initialize
7
+ super
8
+ @thread_maximum = 1
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module RSpec
2
+ module Parallel
3
+ class ConfigurationOptions < RSpec::Core::ConfigurationOptions
4
+ UNFORCED_OPTIONS = [
5
+ :requires, :profile, :drb, :libs, :files_or_directories_to_run,
6
+ :full_description, :full_backtrace, :tty, :thread_maximum
7
+ ].to_set
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,49 @@
1
+ module RSpec
2
+ module Parallel
3
+ # ExampleGroupThreadRunner is a class used to execute [ExampleGroup]
4
+ # classes in parallel as part of rspec-core. When running in parallel
5
+ # the order of example groups will not be honoured.
6
+ # This class is used to ensure that we have a way of keeping track of
7
+ # the number of threads being created and preventing utilization of
8
+ # more than the specified number
9
+ # Additionally, this class will contain a mutex used to prevent access
10
+ # to shared variables within sub-threads
11
+ class ExampleGroupThreadRunner
12
+ attr_accessor :thread_array, :max_threads, :mutex, :used_threads
13
+
14
+ # Creates a new instance of ExampleGroupThreadRunner.
15
+ # @param max_threads [Integer] the maximum limit of threads that can be used
16
+ # @param mutex [Mutex] a semaphore used to prevent access to shared variables in
17
+ # sub-threads such as those used by [ExampleThreadRunner]
18
+ # @param used_threads [Integer] the current number of threads being used
19
+ def initialize(max_threads = 1, mutex = Mutex.new, used_threads = 0)
20
+ @max_threads = max_threads
21
+ @mutex = mutex
22
+ @used_threads = used_threads
23
+ @thread_array = []
24
+ end
25
+
26
+ # Method will run an [ExampleGroup] inside a [Thread] to prevent blocking
27
+ # execution. The new [Thread] is added to an array for tracking and
28
+ # will automatically remove itself when done
29
+ # @param example_group [ExampleGroup] the group to be run inside a [Thread]
30
+ # @param reporter [Reporter] the passed in reporting class used for
31
+ # tracking
32
+ def run(example_group, reporter)
33
+ @thread_array.push Thread.start {
34
+ example_group.run_parallel(reporter, @max_threads, @mutex, @used_threads)
35
+ @thread_array.delete Thread.current
36
+ }
37
+ end
38
+
39
+ # Method will wait for all threads to complete. On completion threads
40
+ # remove themselves from the @thread_array so an empty array means they
41
+ # completed
42
+ def wait_for_completion
43
+ @thread_array.each do |t|
44
+ t.join
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,55 @@
1
+ module RSpec
2
+ module Parallel
3
+ # ExampleThreadRunner is a class used to execute [Example] classes in
4
+ # parallel as part of rspec-core. When running in parallel the order
5
+ # of examples will not be honoured.
6
+ # This class is used to ensure that we have a way of keeping track of
7
+ # the number of threads being created and preventing utilization of
8
+ # more than the specified number
9
+ class ExampleThreadRunner
10
+ attr_accessor :num_threads, :thread_array, :used_threads
11
+
12
+ # Creates a new instance of ExampleThreadRunner.
13
+ # @param num_threads [Integer] the maximum limit of threads that can be used
14
+ # @param used_threads [Integer] the current number of threads being used
15
+ def initialize(num_threads, used_threads)
16
+ @num_threads = num_threads
17
+ @thread_array = []
18
+ @used_threads = used_threads
19
+ end
20
+
21
+ # Method will check global utilization of threads and if that number is
22
+ # at or over the allocated maximum it will wait until a thread is available
23
+ def wait_for_available_thread
24
+ while @used_threads.to_i >= @num_threads.to_i
25
+ sleep 0.1
26
+ end
27
+ end
28
+
29
+ # Method will run the specified example within an available thread or
30
+ # will wait for a thread to become available if none currently are
31
+ # @param example [Example] the example to be executed in a [Thread]
32
+ # @param instance the instance of an ExampleGroup subclass
33
+ # @param reporter [Reporter] the passed in reporting class used for
34
+ # tracking
35
+ def run(example, instance, reporter)
36
+ wait_for_available_thread
37
+ @thread_array.push Thread.start {
38
+ example.run(instance, reporter)
39
+ @thread_array.delete Thread.current # remove from local scope
40
+ @used_threads -= 1
41
+ }
42
+ @used_threads += 1
43
+ end
44
+
45
+ # Method will wait for all threads to complete. On completion threads
46
+ # remove themselves from the @thread_array so an empty array means they
47
+ # completed
48
+ def wait_for_completion
49
+ @thread_array.each do |t|
50
+ t.join
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,213 @@
1
+ module RSpec
2
+ module Parallel
3
+ class Parser < RSpec::Core::Parser
4
+ def parser(options)
5
+ OptionParser.new do |parser|
6
+ parser.banner = "Usage: rspec [options] [files or directories]\n\n"
7
+
8
+ parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |dir|
9
+ options[:libs] ||= []
10
+ options[:libs] << dir
11
+ end
12
+
13
+ parser.on('-r', '--require PATH', 'Require a file.') do |path|
14
+ options[:requires] ||= []
15
+ options[:requires] << path
16
+ end
17
+
18
+ parser.on('-O', '--options PATH', 'Specify the path to a custom options file.') do |path|
19
+ options[:custom_options_file] = path
20
+ end
21
+
22
+ parser.on('--order TYPE[:SEED]', 'Run examples by the specified order type.',
23
+ ' [defined] examples and groups are run in the order they are defined',
24
+ ' [rand] randomize the order of groups and examples',
25
+ ' [random] alias for rand',
26
+ ' [random:SEED] e.g. --order random:123') do |o|
27
+ options[:order] = o
28
+ end
29
+
30
+ parser.on('--seed SEED', Integer, 'Equivalent of --order rand:SEED.') do |seed|
31
+ options[:order] = "rand:#{seed}"
32
+ end
33
+
34
+ parser.on('--fail-fast', 'Abort the run on first failure.') do |o|
35
+ options[:fail_fast] = true
36
+ end
37
+
38
+ parser.on('--no-fail-fast', 'Do not abort the run on first failure.') do |o|
39
+ options[:fail_fast] = false
40
+ end
41
+
42
+ parser.on('--failure-exit-code CODE', Integer, 'Override the exit code used when there are failing specs.') do |code|
43
+ options[:failure_exit_code] = code
44
+ end
45
+
46
+ parser.on('--dry-run', 'Print the formatter output of your suite without',
47
+ ' running any examples or hooks') do |o|
48
+ options[:dry_run] = true
49
+ end
50
+
51
+ parser.on('-X', '--[no-]drb', 'Run examples via DRb.') do |o|
52
+ options[:drb] = o
53
+ end
54
+
55
+ parser.on('--drb-port PORT', 'Port to connect to the DRb server.') do |o|
56
+ options[:drb_port] = o.to_i
57
+ end
58
+
59
+ parser.on('--init', 'Initialize your project with RSpec.') do |cmd|
60
+ RSpec::Support.require_rspec_core "project_initializer"
61
+ ProjectInitializer.new.run
62
+ exit
63
+ end
64
+
65
+ parser.separator("\n **** Output ****\n\n")
66
+
67
+ parser.on('-f', '--format FORMATTER', 'Choose a formatter.',
68
+ ' [p]rogress (default - dots)',
69
+ ' [d]ocumentation (group and example names)',
70
+ ' [h]tml',
71
+ ' [j]son',
72
+ ' custom formatter class name') do |o|
73
+ options[:formatters] ||= []
74
+ options[:formatters] << [o]
75
+ end
76
+
77
+ parser.on('-o', '--out FILE',
78
+ 'Write output to a file instead of $stdout. This option applies',
79
+ ' to the previously specified --format, or the default format',
80
+ ' if no format is specified.'
81
+ ) do |o|
82
+ options[:formatters] ||= [['progress']]
83
+ options[:formatters].last << o
84
+ end
85
+
86
+ parser.on('--deprecation-out FILE', 'Write deprecation warnings to a file instead of $stderr.') do |file|
87
+ options[:deprecation_stream] = file
88
+ end
89
+
90
+ parser.on('-b', '--backtrace', 'Enable full backtrace.') do |o|
91
+ options[:full_backtrace] = true
92
+ end
93
+
94
+ parser.on('-c', '--[no-]color', '--[no-]colour', 'Enable color in the output.') do |o|
95
+ options[:color] = o
96
+ end
97
+
98
+ parser.on('-p', '--[no-]profile [COUNT]', 'Enable profiling of examples and list the slowest examples (default: 10).') do |argument|
99
+ options[:profile_examples] = if argument.nil?
100
+ true
101
+ elsif argument == false
102
+ false
103
+ else
104
+ begin
105
+ Integer(argument)
106
+ rescue ArgumentError
107
+ RSpec.warning "Non integer specified as profile count, seperate " +
108
+ "your path from options with -- e.g. " +
109
+ "`rspec --profile -- #{argument}`",
110
+ :call_site => nil
111
+ true
112
+ end
113
+ end
114
+ end
115
+
116
+ parser.on('-w', '--warnings', 'Enable ruby warnings') do
117
+ $VERBOSE = true
118
+ end
119
+
120
+ parser.on('--parallel-test NUMBER', 'Run the tests with the specified number of parallel threads (default: 1).') do |n|
121
+ options[:thread_maximum] = if !n.nil?
122
+ begin
123
+ Integer(n)
124
+ rescue ArgumentError
125
+ RSpec.warning "Non integer specified as number of parallel threads, seperate " +
126
+ "your path from options with a space e.g. " +
127
+ "`rspec --parallel-test #{n}`",
128
+ :call_site => nil
129
+ 1
130
+ end
131
+ end
132
+ end
133
+
134
+ parser.separator <<-FILTERING
135
+
136
+ **** Filtering/tags ****
137
+
138
+ In addition to the following options for selecting specific files, groups,
139
+ or examples, you can select a single example by appending the line number to
140
+ the filename:
141
+
142
+ rspec path/to/a_spec.rb:37
143
+
144
+ FILTERING
145
+
146
+ parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
147
+ options[:pattern] = o
148
+ end
149
+
150
+ parser.on('-e', '--example STRING', "Run examples whose full nested names include STRING (may be",
151
+ " used more than once)") do |o|
152
+ (options[:full_description] ||= []) << Regexp.compile(Regexp.escape(o))
153
+ end
154
+
155
+ parser.on('-t', '--tag TAG[:VALUE]',
156
+ 'Run examples with the specified tag, or exclude examples',
157
+ 'by adding ~ before the tag.',
158
+ ' - e.g. ~slow',
159
+ ' - TAG is always converted to a symbol') do |tag|
160
+ filter_type = tag =~ /^~/ ? :exclusion_filter : :inclusion_filter
161
+
162
+ name,value = tag.gsub(/^(~@|~|@)/, '').split(':',2)
163
+ name = name.to_sym
164
+
165
+ options[filter_type] ||= {}
166
+ options[filter_type][name] = case value
167
+ when nil then true # The default value for tags is true
168
+ when 'true' then true
169
+ when 'false' then false
170
+ when 'nil' then nil
171
+ when /^:/ then value[1..-1].to_sym
172
+ when /^\d+$/ then Integer(value)
173
+ when /^\d+.\d+$/ then Float(value)
174
+ else
175
+ value
176
+ end
177
+ end
178
+
179
+ parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
180
+ ' be a path to a file or a directory).') do |path|
181
+ options[:default_path] = path
182
+ end
183
+
184
+ parser.separator("\n **** Utility ****\n\n")
185
+
186
+ parser.on('-v', '--version', 'Display the version.') do
187
+ puts RSpec::Core::Version::STRING
188
+ exit
189
+ end
190
+
191
+ # these options would otherwise be confusing to users, so we forcibly prevent them from executing
192
+ # --I is too similar to -I
193
+ # -d was a shorthand for --debugger, which is removed, but now would trigger --default-path
194
+ invalid_options = %w[-d --I]
195
+
196
+ parser.on_tail('-h', '--help', "You're looking at it.") do
197
+ # removing the blank invalid options from the output
198
+ puts parser.to_s.gsub(/^\s+(#{invalid_options.join('|')})\s*$\n/,'')
199
+ exit
200
+ end
201
+
202
+ # this prevents usage of the invalid_options
203
+ invalid_options.each do |option|
204
+ parser.on(option) do
205
+ raise OptionParser::InvalidOption.new
206
+ end
207
+ end
208
+
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,51 @@
1
+ module RSpec
2
+ module Parallel
3
+ class Runner < RSpec::Core::Runner
4
+ # Run a suite of RSpec examples.
5
+ #
6
+ # This is used internally by RSpec to run a suite, but is available
7
+ # for use by any other automation tool.
8
+ #
9
+ # If you want to run this multiple times in the same process, and you
10
+ # want files like spec_helper.rb to be reloaded, be sure to load `load`
11
+ # instead of `require`.
12
+ #
13
+ # #### Parameters
14
+ # * +args+ - an array of command-line-supported arguments
15
+ # * +err+ - error stream (Default: $stderr)
16
+ # * +out+ - output stream (Default: $stdout)
17
+ #
18
+ # #### Returns
19
+ # * +Fixnum+ - exit status code (0/1)
20
+ def self.run(args, err=$stderr, out=$stdout)
21
+ trap_interrupt
22
+ options = ConfigurationOptions.new(args)
23
+ options.parse_options
24
+
25
+ parallel = (options.options[:thread_maximum].nil?) ? false : true
26
+
27
+ if options.options[:drb]
28
+ require 'rspec/core/drb_command_line'
29
+ begin
30
+ DRbCommandLine.new(options).run(err, out)
31
+ rescue DRb::DRbConnError
32
+ err.puts "No DRb server is running. Running in local process instead ..."
33
+ if parallel
34
+ CommandLine.new(options).run_parallel(err, out)
35
+ else
36
+ CommandLine.new(options).run(err, out)
37
+ end
38
+ end
39
+ else
40
+ if parallel
41
+ CommandLine.new(options).run_parallel(err, out)
42
+ else
43
+ CommandLine.new(options).run(err, out)
44
+ end
45
+ end
46
+ ensure
47
+ RSpec.reset
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,9 @@
1
+ module RSpec
2
+ module Parallel
3
+ # Version information for RSpec Parallel.
4
+ module Version
5
+ # Current version of RSpec Parallel, in semantic versioning format.
6
+ STRING = '2.14.8.1'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,79 @@
1
+ require 'rspec'
2
+ require_rspec = if defined?(require_relative)
3
+ lambda do |path|
4
+ require_relative path
5
+ end
6
+ else
7
+ lambda do |path|
8
+ require "rspec/#{path}"
9
+ end
10
+ end
11
+
12
+ require_rspec['parallel/version']
13
+ require_rspec['parallel/configuration']
14
+ require_rspec['parallel/option_parser']
15
+ require_rspec['parallel/configuration_options']
16
+ require_rspec['parallel/example_thread_runner']
17
+ require_rspec['parallel/example_group_thread_runner']
18
+ require_rspec['parallel/runner']
19
+
20
+ module RSpec
21
+ # Returns the global [Configuration](RSpec/Parallel/Configuration) object. While you
22
+ # _can_ use this method to access the configuration, the more common
23
+ # convention is to use [RSpec.configure](RSpec#configure-class_method).
24
+ #
25
+ # @example
26
+ # RSpec.configuration.drb_port = 1234
27
+ # @see RSpec.configure
28
+ # @see Parallel::Configuration
29
+ def self.configuration
30
+ @configuration ||= begin
31
+ config = RSpec::Parallel::Configuration.new
32
+ config.expose_dsl_globally = true
33
+ config
34
+ end
35
+
36
+ end
37
+
38
+ module Parallel
39
+ class << RSpec::Core::ExampleGroup
40
+ # Runs all the examples in this group in a separate thread for each
41
+ def run_parallel(reporter, num_threads, mutex, used_threads)
42
+ if RSpec.wants_to_quit
43
+ RSpec.clear_remaining_example_groups if top_level?
44
+ return
45
+ end
46
+ reporter.example_group_started(self)
47
+
48
+ begin
49
+ run_before_all_hooks(new)
50
+ example_threads = RSpec::Parallel::ExampleThreadRunner.new(num_threads, used_threads)
51
+ run_examples_parallel(reporter, example_threads, mutex)
52
+ children.ordered.map {|child| child.run_parallel(reporter, num_threads, mutex, used_threads)}
53
+ example_threads.wait_for_completion
54
+ rescue Exception => ex
55
+ RSpec.wants_to_quit = true if fail_fast?
56
+ fail_filtered_examples(ex, reporter)
57
+ ensure
58
+ run_after_all_hooks(new)
59
+ before_all_ivars.clear
60
+ reporter.example_group_finished(self)
61
+ end
62
+ end
63
+
64
+ # @private
65
+ # Runs the examples in this group in a separate thread each
66
+ def run_examples_parallel(reporter, threads, mutex)
67
+ filtered_examples.ordered.map do |example|
68
+ next if RSpec.wants_to_quit
69
+ instance = new
70
+ set_ivars(instance, before_all_ivars)
71
+ mutex.synchronize do
72
+ threads.run(example, instance, reporter)
73
+ end
74
+ RSpec.wants_to_quit = true if fail_fast?
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec-parallel
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.14.8.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jason Holt Smith
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.14.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 2.14.0
30
+ description: Bolt-on gem allowing for parallel execution of examples using rspec's
31
+ framework
32
+ email: bicarbon8@gmail.com
33
+ executables:
34
+ - rspec
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - lib/rspec/parallel.rb
39
+ - lib/rspec/parallel/autorun.rb
40
+ - lib/rspec/parallel/command_line.rb
41
+ - lib/rspec/parallel/configuration.rb
42
+ - lib/rspec/parallel/configuration_options.rb
43
+ - lib/rspec/parallel/example_group_thread_runner.rb
44
+ - lib/rspec/parallel/example_thread_runner.rb
45
+ - lib/rspec/parallel/option_parser.rb
46
+ - lib/rspec/parallel/runner.rb
47
+ - lib/rspec/parallel/version.rb
48
+ - bin/rspec
49
+ homepage: https://github.com/bicarbon8/rspec-parallel.git
50
+ licenses:
51
+ - MIT
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.8.7
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 1.8.23
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Parallel rspec execution gem
74
+ test_files: []
75
+ has_rdoc: