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 +25 -0
- data/lib/rspec/parallel/autorun.rb +2 -0
- data/lib/rspec/parallel/command_line.rb +44 -0
- data/lib/rspec/parallel/configuration.rb +12 -0
- data/lib/rspec/parallel/configuration_options.rb +10 -0
- data/lib/rspec/parallel/example_group_thread_runner.rb +49 -0
- data/lib/rspec/parallel/example_thread_runner.rb +55 -0
- data/lib/rspec/parallel/option_parser.rb +213 -0
- data/lib/rspec/parallel/runner.rb +51 -0
- data/lib/rspec/parallel/version.rb +9 -0
- data/lib/rspec/parallel.rb +79 -0
- metadata +75 -0
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,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,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,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:
|