rspec-core 3.7.1 → 3.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +116 -0
- data/README.md +18 -18
- data/lib/rspec/core.rb +1 -0
- data/lib/rspec/core/bisect/coordinator.rb +26 -30
- data/lib/rspec/core/bisect/example_minimizer.rb +12 -8
- data/lib/rspec/core/bisect/fork_runner.rb +138 -0
- data/lib/rspec/core/bisect/server.rb +5 -14
- data/lib/rspec/core/bisect/{runner.rb → shell_command.rb} +27 -70
- data/lib/rspec/core/bisect/shell_runner.rb +73 -0
- data/lib/rspec/core/bisect/utilities.rb +58 -0
- data/lib/rspec/core/configuration.rb +236 -79
- data/lib/rspec/core/configuration_options.rb +41 -4
- data/lib/rspec/core/did_you_mean.rb +46 -0
- data/lib/rspec/core/example.rb +18 -8
- data/lib/rspec/core/example_group.rb +33 -16
- data/lib/rspec/core/filter_manager.rb +1 -1
- data/lib/rspec/core/formatters.rb +14 -6
- data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
- data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +29 -16
- data/lib/rspec/core/formatters/deprecation_formatter.rb +3 -1
- data/lib/rspec/core/formatters/documentation_formatter.rb +35 -3
- data/lib/rspec/core/formatters/exception_presenter.rb +29 -6
- data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
- data/lib/rspec/core/formatters/html_printer.rb +0 -2
- data/lib/rspec/core/formatters/protocol.rb +17 -17
- data/lib/rspec/core/formatters/syntax_highlighter.rb +19 -19
- data/lib/rspec/core/hooks.rb +44 -24
- data/lib/rspec/core/invocations.rb +9 -7
- data/lib/rspec/core/memoized_helpers.rb +33 -14
- data/lib/rspec/core/metadata.rb +2 -3
- data/lib/rspec/core/option_parser.rb +10 -3
- data/lib/rspec/core/profiler.rb +3 -1
- data/lib/rspec/core/rake_task.rb +22 -2
- data/lib/rspec/core/reporter.rb +11 -6
- data/lib/rspec/core/runner.rb +25 -14
- data/lib/rspec/core/shared_example_group.rb +5 -5
- data/lib/rspec/core/shell_escape.rb +2 -2
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +14 -1
- metadata +25 -15
- metadata.gz.sig +0 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30e931022769b69911776a8c64de53481785df0074e84693b5e4031c20a53bb2
|
4
|
+
data.tar.gz: 9d5f23168383bff0e8f3152d9e111ed7600ee1cefb9ccaeb6c1a0fa384dfe3b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50a9d24a978ca5c0e13bccb4b10343aeac24d2895692d0a2c7d3a6ab429213ede9b9406d4deca6d7cb496f91919eb38fe711ca0294eb94d26e60e4c07abb2e4b
|
7
|
+
data.tar.gz: e412bad1efb696f88065ba2adab372ef8e613ece6f70dd8bf193daeab5e3c8ea41978d3d2b3f5829c4a11c3eb3e2f01428f979d8b75f1f658dc4dcb78fdbf263
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/Changelog.md
CHANGED
@@ -1,3 +1,118 @@
|
|
1
|
+
# 3.9.3 / 2020-09-30
|
2
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.2...v3.9.3)
|
3
|
+
|
4
|
+
Bug Fixes:
|
5
|
+
|
6
|
+
* Declare `ruby2_keywords` on `method_missing` for other gems. (Jon Rowe, #2731)
|
7
|
+
* Ensure custom error codes are returned from bisect runs. (Jon Rowe, #2732)
|
8
|
+
* Ensure `RSpec::Core::Configuration` predicate config methods return booleans.
|
9
|
+
(Marc-André Lafortune, #2736)
|
10
|
+
* Prevent `rspec --bisect` from generating zombie processes while executing
|
11
|
+
bisect runs. (Benoit Tigeot, Jon Rowe, #2739)
|
12
|
+
* Predicates for pending examples, (in `RSpec::Core::Example`, `#pending?`, `#skipped?` and
|
13
|
+
`#pending_fixed?`) now return boolean values rather than truthy values.
|
14
|
+
(Marc-André Lafortune, #2756, #2758)
|
15
|
+
* Exceptions which have a message which cannot be cast to a string will no longer
|
16
|
+
cause a crash. (Jon Rowe, #2761)
|
17
|
+
|
18
|
+
### 3.9.2 / 2020-05-02
|
19
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.1...v3.9.2)
|
20
|
+
|
21
|
+
Bug Fixes:
|
22
|
+
|
23
|
+
* Emit a warning when `around` hook is used with `:context` scope
|
24
|
+
(Phil Pirozhkov, #2687)
|
25
|
+
* Prevent invalid implementations of `Exception#cause` from being treated as a
|
26
|
+
valid cause (and causing strange errors) in `RSpec::Core::Formatters::ExceptionPresenter`.
|
27
|
+
(Jon Rowe, #2703)
|
28
|
+
* Correctly detect patterns when `rspec_opts` is an array in `RSpec::Core::RakeTask`.
|
29
|
+
(Marc-André Lafortune, #2704)
|
30
|
+
* Make `RSpec.clear_examples` reset example counts for example groups. This fixes
|
31
|
+
an issue with re-running specs not matching ids. (Agis Anastasopoulos, #2723)
|
32
|
+
|
33
|
+
### 3.9.1 / 2019-12-28
|
34
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.9.0...v3.9.1)
|
35
|
+
|
36
|
+
Bug Fixes:
|
37
|
+
|
38
|
+
* Prevent bisect command from blocking when number of specs exceeds file
|
39
|
+
descriptor limit on OSX or Linux. (Benoit Tigeot, #2669)
|
40
|
+
* Prevent warnings being issued on Ruby 2.7.0. (Jon Rowe, #2680)
|
41
|
+
|
42
|
+
### 3.9.0 / 2019-10-07
|
43
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.2...v3.9.0)
|
44
|
+
|
45
|
+
Enhancements:
|
46
|
+
|
47
|
+
* Improve the handling of errors during loading support files, if a file
|
48
|
+
errors before loading specs, RSpec will now skip loading the specs.
|
49
|
+
(David Rodríguez, #2568)
|
50
|
+
* Add support for --example-matches to run examples by regular expression.
|
51
|
+
(Sam Joseph, Matt Rider, @okothkongo1, #2586)
|
52
|
+
* Add `did_you_mean` suggestions for file names encountering a `LoadError`
|
53
|
+
outside of examples. (@obromios, #2601)
|
54
|
+
* Add a minimalist quick fix style formatter, only outputs failures as
|
55
|
+
`file:line:message`. (Romain Tartière, #2614)
|
56
|
+
* Convert string number values to integer when used for `RSpec::Configuration#fail_fast`
|
57
|
+
(Viktor Fonic, #2634)
|
58
|
+
* Issue warning when invalid values are used for `RSpec::Configuration#fail_fast`
|
59
|
+
(Viktor Fonic, #2634)
|
60
|
+
* Add support for running the Rake task in a clean environment.
|
61
|
+
(Jon Rowe, #2632)
|
62
|
+
* Indent messages by there example group / example in the documentation formatter.
|
63
|
+
(Samuel Williams, #2649)
|
64
|
+
|
65
|
+
### 3.8.2 / 2019-06-29
|
66
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.1...v3.8.2)
|
67
|
+
|
68
|
+
Bug Fixes:
|
69
|
+
|
70
|
+
* Fix `config.define_derived_metadata` so that cascades are not triggered
|
71
|
+
until metadata has been assigned to the example or example group
|
72
|
+
(Myron Marston, #2635).
|
73
|
+
|
74
|
+
### 3.8.1 / 2019-06-13
|
75
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.8.0...v3.8.1)
|
76
|
+
|
77
|
+
Bug Fixes:
|
78
|
+
|
79
|
+
* Handle RSpec description(s) with japanese chars in CP932 encoded files.
|
80
|
+
(Benoit Tigeot, #2575)
|
81
|
+
* When defining `let` methods that overwrite an existing method, prevent
|
82
|
+
a warning being issued by removing the old definition. (Jon Rowe, #2593)
|
83
|
+
* Prevent warning on Ruby 2.6.0-rc1 (Keiji Yoshimi, #2582)
|
84
|
+
* Fix `config.define_derived_metadata` so that it supports cascades.
|
85
|
+
(Myron Marston, #2630).
|
86
|
+
|
87
|
+
### 3.8.0 / 2018-08-04
|
88
|
+
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.1...v3.8.0)
|
89
|
+
|
90
|
+
Enhancements:
|
91
|
+
|
92
|
+
* Improve shell escaping used by `RSpec::Core::RakeTask` and `--bisect` so
|
93
|
+
that it works on `Pathname` objects. (Andrew Vit, #2479)
|
94
|
+
* Nicely format errors encountered while loading files specified
|
95
|
+
by `--require` option. (Myron Marston, #2504)
|
96
|
+
* Significantly improve the performance of `--bisect` on platforms that
|
97
|
+
support forking by replacing the shell-based runner with one that uses
|
98
|
+
forking so that RSpec and the application environment can be booted only
|
99
|
+
once, instead of once per spec run. (Myron Marston, #2511)
|
100
|
+
* Provide a configuration API to pick which bisect runner is used for
|
101
|
+
`--bisect`. Pick a runner via `config.bisect_runner = :shell` or
|
102
|
+
`config.bisect_runner = :fork` in a file loaded by a `--require`
|
103
|
+
option passed at the command line or set in `.rspec`. (Myron Marston, #2511)
|
104
|
+
* Support the [XDG Base Directory
|
105
|
+
Specification](https://specifications.freedesktop.org/basedir-spec/latest/)
|
106
|
+
for the global options file. `~/.rspec` is still supported when no
|
107
|
+
options file is found in `$XDG_CONFIG_HOME/rspec/options` (Magnus Bergmark, #2538)
|
108
|
+
* Extract `RSpec.world.prepare_example_filtering` that sets up the
|
109
|
+
example filtering for custom RSpec runners. (Oleg Pudeyev, #2552)
|
110
|
+
|
111
|
+
Bug Fixes:
|
112
|
+
|
113
|
+
* Prevent an `ArgumentError` when truncating backtraces with two identical
|
114
|
+
backtraces. (Systho, #2515, Benoit Tigeot, #2539)
|
115
|
+
|
1
116
|
### 3.7.1 / 2018-01-02
|
2
117
|
[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.7.0...v3.7.1)
|
3
118
|
|
@@ -2046,6 +2161,7 @@ Bug fixes
|
|
2046
2161
|
[Full Changelog](http://github.com/rspec/rspec-core/compare/v2.2.0...v2.2.1)
|
2047
2162
|
|
2048
2163
|
Bug fixes
|
2164
|
+
|
2049
2165
|
* alias_method instead of override Kernel#method_missing (John Wilger)
|
2050
2166
|
* changed --autotest to --tty in generated command (MIKAMI Yoshiyuki)
|
2051
2167
|
* revert change to debugger (had introduced conflict with Rails)
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.svg?branch=
|
1
|
+
# rspec-core [![Build Status](https://secure.travis-ci.org/rspec/rspec-core.svg?branch=main)](http://travis-ci.org/rspec/rspec-core) [![Code Climate](https://codeclimate.com/github/rspec/rspec-core.svg)](https://codeclimate.com/github/rspec/rspec-core)
|
2
2
|
|
3
3
|
rspec-core provides the structure for writing executable examples of how your
|
4
4
|
code should behave, and an `rspec` command with tools to constrain which
|
@@ -10,29 +10,15 @@ examples get run and tailor the output.
|
|
10
10
|
gem install rspec-core # for rspec-core only
|
11
11
|
rspec --help
|
12
12
|
|
13
|
-
Want to run against the `
|
13
|
+
Want to run against the `main` branch? You'll need to include the dependent
|
14
14
|
RSpec repos as well. Add the following to your `Gemfile`:
|
15
15
|
|
16
16
|
```ruby
|
17
17
|
%w[rspec rspec-core rspec-expectations rspec-mocks rspec-support].each do |lib|
|
18
|
-
gem lib, :git => "
|
18
|
+
gem lib, :git => "https://github.com/rspec/#{lib}.git", :branch => 'main'
|
19
19
|
end
|
20
20
|
```
|
21
21
|
|
22
|
-
## Contributing
|
23
|
-
|
24
|
-
Once you've set up the environment, you'll need to cd into the working
|
25
|
-
directory of whichever repo you want to work in. From there you can run the
|
26
|
-
specs and cucumber features, and make patches.
|
27
|
-
|
28
|
-
NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
|
29
|
-
can treat each RSpec repo as an independent project.
|
30
|
-
|
31
|
-
* [Build details](BUILD_DETAIL.md)
|
32
|
-
* [Code of Conduct](CODE_OF_CONDUCT.md)
|
33
|
-
* [Detailed contributing guide](CONTRIBUTING.md)
|
34
|
-
* [Development setup guide](DEVELOPMENT.md)
|
35
|
-
|
36
22
|
## Basic Structure
|
37
23
|
|
38
24
|
RSpec uses the words "describe" and "it" so we can express concepts like a conversation:
|
@@ -67,7 +53,7 @@ context of an _instance_ of that class.
|
|
67
53
|
|
68
54
|
## Nested Groups
|
69
55
|
|
70
|
-
You can also declare nested
|
56
|
+
You can also declare nested groups using the `describe` or `context`
|
71
57
|
methods:
|
72
58
|
|
73
59
|
```ruby
|
@@ -376,6 +362,20 @@ Finished in 0.000379 seconds
|
|
376
362
|
1 example, 0 failures
|
377
363
|
```
|
378
364
|
|
365
|
+
## Contributing
|
366
|
+
|
367
|
+
Once you've set up the environment, you'll need to cd into the working
|
368
|
+
directory of whichever repo you want to work in. From there you can run the
|
369
|
+
specs and cucumber features, and make patches.
|
370
|
+
|
371
|
+
NOTE: You do not need to use rspec-dev to work on a specific RSpec repo. You
|
372
|
+
can treat each RSpec repo as an independent project.
|
373
|
+
|
374
|
+
* [Build details](BUILD_DETAIL.md)
|
375
|
+
* [Code of Conduct](CODE_OF_CONDUCT.md)
|
376
|
+
* [Detailed contributing guide](CONTRIBUTING.md)
|
377
|
+
* [Development setup guide](DEVELOPMENT.md)
|
378
|
+
|
379
379
|
## Also see
|
380
380
|
|
381
381
|
* [https://github.com/rspec/rspec](https://github.com/rspec/rspec)
|
data/lib/rspec/core.rb
CHANGED
@@ -139,6 +139,7 @@ module RSpec
|
|
139
139
|
module Core
|
140
140
|
autoload :ExampleStatusPersister, "rspec/core/example_status_persister"
|
141
141
|
autoload :Profiler, "rspec/core/profiler"
|
142
|
+
autoload :DidYouMean, "rspec/core/did_you_mean"
|
142
143
|
|
143
144
|
# @private
|
144
145
|
# This avoids issues with reporting time caused by examples that
|
@@ -1,62 +1,58 @@
|
|
1
|
-
RSpec::Support.require_rspec_core "bisect/
|
2
|
-
RSpec::Support.require_rspec_core "bisect/runner"
|
1
|
+
RSpec::Support.require_rspec_core "bisect/shell_command"
|
3
2
|
RSpec::Support.require_rspec_core "bisect/example_minimizer"
|
3
|
+
RSpec::Support.require_rspec_core "bisect/utilities"
|
4
4
|
RSpec::Support.require_rspec_core "formatters/bisect_progress_formatter"
|
5
5
|
|
6
6
|
module RSpec
|
7
7
|
module Core
|
8
8
|
module Bisect
|
9
|
-
# @private
|
10
9
|
# The main entry point into the bisect logic. Coordinates among:
|
11
|
-
# - Bisect::
|
12
|
-
# - Bisect::Runner: Runs a set of examples and directs the results
|
13
|
-
# to the server.
|
10
|
+
# - Bisect::ShellCommand: Generates shell commands to run spec subsets
|
14
11
|
# - Bisect::ExampleMinimizer: Contains the core bisect logic.
|
15
|
-
# -
|
16
|
-
#
|
12
|
+
# - A bisect runner: runs a set of examples and returns the results.
|
13
|
+
# - A bisect formatter: provides progress updates to the user.
|
14
|
+
# @private
|
17
15
|
class Coordinator
|
18
|
-
def self.bisect_with(
|
19
|
-
new(
|
16
|
+
def self.bisect_with(spec_runner, original_cli_args, formatter)
|
17
|
+
new(spec_runner, original_cli_args, formatter).bisect
|
20
18
|
end
|
21
19
|
|
22
|
-
def initialize(
|
23
|
-
@
|
24
|
-
@
|
25
|
-
@
|
20
|
+
def initialize(spec_runner, original_cli_args, formatter)
|
21
|
+
@spec_runner = spec_runner
|
22
|
+
@shell_command = ShellCommand.new(original_cli_args)
|
23
|
+
@notifier = Bisect::Notifier.new(formatter)
|
26
24
|
end
|
27
25
|
|
28
26
|
def bisect
|
29
|
-
|
30
|
-
|
31
|
-
reporter.close_after do
|
32
|
-
repro = Server.run do |server|
|
33
|
-
runner = Runner.new(server, @original_cli_args)
|
34
|
-
minimizer = ExampleMinimizer.new(runner, reporter)
|
27
|
+
repro = start_bisect_runner do |runner|
|
28
|
+
minimizer = ExampleMinimizer.new(@shell_command, runner, @notifier)
|
35
29
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
reporter.publish(:bisect_repro_command, :repro => repro)
|
30
|
+
gracefully_abort_on_sigint(minimizer)
|
31
|
+
minimizer.find_minimal_repro
|
32
|
+
minimizer.repro_command_for_currently_needed_ids
|
42
33
|
end
|
43
34
|
|
35
|
+
@notifier.publish(:bisect_repro_command, :repro => repro)
|
36
|
+
|
44
37
|
true
|
45
38
|
rescue BisectFailedError => e
|
46
|
-
|
39
|
+
@notifier.publish(:bisect_failed, :failure_explanation => e.message)
|
47
40
|
false
|
41
|
+
ensure
|
42
|
+
@notifier.publish(:close)
|
48
43
|
end
|
49
44
|
|
50
45
|
private
|
51
46
|
|
52
|
-
def
|
53
|
-
@configuration.
|
47
|
+
def start_bisect_runner(&block)
|
48
|
+
klass = @spec_runner.configuration.bisect_runner_class
|
49
|
+
klass.start(@shell_command, @spec_runner, &block)
|
54
50
|
end
|
55
51
|
|
56
52
|
def gracefully_abort_on_sigint(minimizer)
|
57
53
|
trap('INT') do
|
58
54
|
repro = minimizer.repro_command_for_currently_needed_ids
|
59
|
-
|
55
|
+
@notifier.publish(:bisect_aborted, :repro => repro)
|
60
56
|
exit(1)
|
61
57
|
end
|
62
58
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "bisect/utilities"
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Core
|
3
5
|
module Bisect
|
@@ -5,12 +7,13 @@ module RSpec
|
|
5
7
|
# Contains the core bisect logic. Searches for examples we can ignore by
|
6
8
|
# repeatedly running different subsets of the suite.
|
7
9
|
class ExampleMinimizer
|
8
|
-
attr_reader :
|
10
|
+
attr_reader :shell_command, :runner, :all_example_ids, :failed_example_ids
|
9
11
|
attr_accessor :remaining_ids
|
10
12
|
|
11
|
-
def initialize(runner,
|
12
|
-
@
|
13
|
-
@
|
13
|
+
def initialize(shell_command, runner, notifier)
|
14
|
+
@shell_command = shell_command
|
15
|
+
@runner = runner
|
16
|
+
@notifier = notifier
|
14
17
|
end
|
15
18
|
|
16
19
|
def find_minimal_repro
|
@@ -82,7 +85,7 @@ module RSpec
|
|
82
85
|
end
|
83
86
|
|
84
87
|
def repro_command_for_currently_needed_ids
|
85
|
-
return
|
88
|
+
return shell_command.repro_command_from(currently_needed_ids) if remaining_ids
|
86
89
|
"(Not yet enough information to provide any repro command)"
|
87
90
|
end
|
88
91
|
|
@@ -108,7 +111,8 @@ module RSpec
|
|
108
111
|
end
|
109
112
|
|
110
113
|
def prep
|
111
|
-
notify(:bisect_starting, :original_cli_args =>
|
114
|
+
notify(:bisect_starting, :original_cli_args => shell_command.original_cli_args,
|
115
|
+
:bisect_runner => runner.class.name)
|
112
116
|
|
113
117
|
_, duration = track_duration do
|
114
118
|
original_results = runner.original_results
|
@@ -135,7 +139,7 @@ module RSpec
|
|
135
139
|
ids_to_run = ids + failed_example_ids
|
136
140
|
notify(
|
137
141
|
:bisect_individual_run_start,
|
138
|
-
:command =>
|
142
|
+
:command => shell_command.repro_command_from(ids_to_run),
|
139
143
|
:ids_to_run => ids_to_run
|
140
144
|
)
|
141
145
|
|
@@ -161,7 +165,7 @@ module RSpec
|
|
161
165
|
end
|
162
166
|
|
163
167
|
def notify(*args)
|
164
|
-
|
168
|
+
@notifier.publish(*args)
|
165
169
|
end
|
166
170
|
end
|
167
171
|
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
RSpec::Support.require_rspec_core "formatters/base_bisect_formatter"
|
3
|
+
RSpec::Support.require_rspec_core "bisect/utilities"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module Core
|
7
|
+
module Bisect
|
8
|
+
# A Bisect runner that runs requested subsets of the suite by forking
|
9
|
+
# sub-processes. The main process bootstraps RSpec and the application
|
10
|
+
# environment (including preloading files specified via `--require`) so
|
11
|
+
# that the individual spec runs do not have to re-pay that cost. Each
|
12
|
+
# spec run happens in a forked process, ensuring that the spec files are
|
13
|
+
# not loaded in the main process.
|
14
|
+
#
|
15
|
+
# For most projects, bisections that use `ForkRunner` instead of
|
16
|
+
# `ShellRunner` will finish significantly faster, because the `ShellRunner`
|
17
|
+
# pays the cost of booting RSpec and the app environment on _every_ run of
|
18
|
+
# a subset. In contrast, `ForkRunner` pays that cost only once.
|
19
|
+
#
|
20
|
+
# However, not all projects can use `ForkRunner`. Obviously, on platforms
|
21
|
+
# that do not support forking (e.g. Windows), it cannot be used. In addition,
|
22
|
+
# it can cause problems for some projects that put side-effectful spec
|
23
|
+
# bootstrapping logic that should run on every spec run directly at the top
|
24
|
+
# level in a file loaded by `--require`, rather than in a `before(:suite)`
|
25
|
+
# hook. For example, consider a project that relies on some top-level logic
|
26
|
+
# in `spec_helper` to boot a Redis server for the test suite, intending the
|
27
|
+
# Redis bootstrapping to happen on every spec run. With `ShellRunner`, the
|
28
|
+
# bootstrapping logic will happen for each run of any subset of the suite,
|
29
|
+
# but for `ForkRunner`, such logic will only get run once, when the
|
30
|
+
# `RunDispatcher` boots the application environment. This might cause
|
31
|
+
# problems. The solution is for users to move the bootstrapping logic into
|
32
|
+
# a `before(:suite)` hook, or use the slower `ShellRunner`.
|
33
|
+
#
|
34
|
+
# @private
|
35
|
+
class ForkRunner
|
36
|
+
def self.start(shell_command, spec_runner)
|
37
|
+
instance = new(shell_command, spec_runner)
|
38
|
+
yield instance
|
39
|
+
ensure
|
40
|
+
instance.shutdown
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.name
|
44
|
+
:fork
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(shell_command, spec_runner)
|
48
|
+
@shell_command = shell_command
|
49
|
+
@channel = Channel.new
|
50
|
+
@run_dispatcher = RunDispatcher.new(spec_runner, @channel)
|
51
|
+
end
|
52
|
+
|
53
|
+
def run(locations)
|
54
|
+
run_descriptor = ExampleSetDescriptor.new(locations, original_results.failed_example_ids)
|
55
|
+
dispatch_run(run_descriptor)
|
56
|
+
end
|
57
|
+
|
58
|
+
def original_results
|
59
|
+
@original_results ||= dispatch_run(ExampleSetDescriptor.new(
|
60
|
+
@shell_command.original_locations, []))
|
61
|
+
end
|
62
|
+
|
63
|
+
def shutdown
|
64
|
+
@channel.close
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def dispatch_run(run_descriptor)
|
70
|
+
@run_dispatcher.dispatch_specs(run_descriptor)
|
71
|
+
@channel.receive.tap do |result|
|
72
|
+
if result.is_a?(String)
|
73
|
+
raise BisectFailedError.for_failed_spec_run(result)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @private
|
79
|
+
class RunDispatcher
|
80
|
+
def initialize(runner, channel)
|
81
|
+
@runner = runner
|
82
|
+
@channel = channel
|
83
|
+
|
84
|
+
@spec_output = StringIO.new
|
85
|
+
|
86
|
+
runner.configuration.tap do |c|
|
87
|
+
c.reset_reporter
|
88
|
+
c.output_stream = @spec_output
|
89
|
+
c.error_stream = @spec_output
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def dispatch_specs(run_descriptor)
|
94
|
+
pid = fork { run_specs(run_descriptor) }
|
95
|
+
# We don't use Process.waitpid here as it was causing bisects to
|
96
|
+
# block due to the file descriptor limit on OSX / Linux. We need
|
97
|
+
# to detach the process to avoid having zombie processes
|
98
|
+
# consuming slots in the kernel process table during bisect runs.
|
99
|
+
Process.detach(pid)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def run_specs(run_descriptor)
|
105
|
+
$stdout = $stderr = @spec_output
|
106
|
+
formatter = CaptureFormatter.new(run_descriptor.failed_example_ids)
|
107
|
+
|
108
|
+
@runner.configuration.tap do |c|
|
109
|
+
c.files_or_directories_to_run = run_descriptor.all_example_ids
|
110
|
+
c.formatter = formatter
|
111
|
+
c.load_spec_files
|
112
|
+
end
|
113
|
+
|
114
|
+
# `announce_filters` has the side effect of implementing the logic
|
115
|
+
# that honors `config.run_all_when_everything_filtered` so we need
|
116
|
+
# to call it here. When we remove `run_all_when_everything_filtered`
|
117
|
+
# (slated for RSpec 4), we can remove this call to `announce_filters`.
|
118
|
+
@runner.world.announce_filters
|
119
|
+
|
120
|
+
@runner.run_specs(@runner.world.ordered_example_groups)
|
121
|
+
latest_run_results = formatter.results
|
122
|
+
|
123
|
+
if latest_run_results.nil? || latest_run_results.all_example_ids.empty?
|
124
|
+
@channel.send(@spec_output.string)
|
125
|
+
else
|
126
|
+
@channel.send(latest_run_results)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class CaptureFormatter < Formatters::BaseBisectFormatter
|
132
|
+
attr_accessor :results
|
133
|
+
alias_method :notify_results, :results=
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|