flatware-rspec 1.2.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -48
- data/lib/flatware/rspec.rb +5 -4
- data/lib/flatware/rspec/checkpoint.rb +42 -10
- data/lib/flatware/rspec/cli.rb +16 -5
- data/lib/flatware/rspec/formatter.rb +23 -15
- data/lib/flatware/rspec/formatters/console.rb +62 -26
- data/lib/flatware/rspec/job_builder.rb +39 -32
- data/lib/flatware/rspec/marshalable.rb +20 -0
- data/lib/flatware/rspec/marshalable/example.rb +26 -0
- data/lib/flatware/rspec/marshalable/example_group.rb +11 -0
- data/lib/flatware/rspec/marshalable/examples_notification.rb +30 -0
- data/lib/flatware/rspec/marshalable/profile_notification.rb +30 -0
- data/lib/flatware/rspec/marshalable/summary_notification.rb +30 -0
- metadata +21 -15
- data/lib/flatware/rspec/example_notification.rb +0 -21
- data/lib/flatware/rspec/examples_notification.rb +0 -24
- data/lib/flatware/rspec/summary.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6a0aaa1271e9e220195b1198be4374e2a3e0a40fbe0dbdb61fad0c4735ab4e0
|
4
|
+
data.tar.gz: 2e16cb3d10ac6a990a393b84e0a3ae04ea4ccccfdbb9de3d1b264d4729a2d32f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b133ea289d7abe6828bf0c7188bb389c113126ea8e79866aed5b973d4213b473f79e219c4f3d151f6c1bbf175fd48790140c531c6ce4eeb488837c4bd1ed618
|
7
|
+
data.tar.gz: 26d0a1a2a322ee2ad2cb4ac9b5d33c42aefdbe15a80d1c108d8e7d8b11a4f50e8bfb36e8003496c3215c939c74c3797f1eca7dad0c11843d96d1e9e1f3f85c3c
|
data/README.md
CHANGED
@@ -7,39 +7,6 @@
|
|
7
7
|
|
8
8
|
Flatware parallelizes your test suite to significantly reduce test time.
|
9
9
|
|
10
|
-
## Requirements
|
11
|
-
|
12
|
-
* ZeroMQ > 4.0
|
13
|
-
|
14
|
-
## Installation
|
15
|
-
|
16
|
-
### ZeroMQ
|
17
|
-
|
18
|
-
#### Linux Ubuntu
|
19
|
-
|
20
|
-
```sh
|
21
|
-
sudo apt-get install -qq libzmq3-dev
|
22
|
-
```
|
23
|
-
|
24
|
-
(Never you mind the 3. This package contains ZMQ version 4.)
|
25
|
-
|
26
|
-
#### Mac OSX
|
27
|
-
|
28
|
-
|
29
|
-
If you're on macOS 10.12, use the custom hashrocket ZMQ homebrew formula.
|
30
|
-
|
31
|
-
```sh
|
32
|
-
brew tap hashrocket/formulas
|
33
|
-
brew install hashrocket/formulas/zeromq
|
34
|
-
```
|
35
|
-
|
36
|
-
The stock homebrew version will likely work on older versions of macOS.
|
37
|
-
|
38
|
-
|
39
|
-
```sh
|
40
|
-
brew install zeromq
|
41
|
-
```
|
42
|
-
|
43
10
|
### Flatware
|
44
11
|
|
45
12
|
Add the runners you need to your Gemfile:
|
@@ -81,8 +48,9 @@ For this to work the configuration option must be loaded before any specs are ru
|
|
81
48
|
|
82
49
|
--require spec_helper
|
83
50
|
|
84
|
-
But beware, if you're using ActiveRecord in your suite you'll need to avoid doing things that cause it to establish a database connection in `spec_helper.rb`. If ActiveRecord connects before flatware forks off workers, each will die messily. All of this will just work if you're following [the recomended pattern of splitting your helpers into `spec_helper` and `rails_helper`](https://github.com/rspec/rspec-rails/blob/v3.8.2/lib/generators/rspec/install/templates/spec/rails_helper.rb).
|
85
|
-
|
51
|
+
But beware, if you're using ActiveRecord in your suite you'll need to avoid doing things that cause it to establish a database connection in `spec_helper.rb`. If ActiveRecord connects before flatware forks off workers, each will die messily. All of this will just work if you're following [the recomended pattern of splitting your helpers into `spec_helper` and `rails_helper`](https://github.com/rspec/rspec-rails/blob/v3.8.2/lib/generators/rspec/install/templates/spec/rails_helper.rb). Another option is to use [the configurable hooks](
|
52
|
+
#faster-startup-with-activerecord
|
53
|
+
).
|
86
54
|
|
87
55
|
### Options
|
88
56
|
|
@@ -134,9 +102,31 @@ Now you are ready to rock:
|
|
134
102
|
$ flatware rspec && flatware cucumber
|
135
103
|
```
|
136
104
|
|
137
|
-
|
105
|
+
### Faster Startup With ActiveRecord
|
106
|
+
|
107
|
+
Flatware has a couple lifecycle callbacks that you can use to avoid booting your app
|
108
|
+
over again on every core. One way to take advantage of this via a `spec/flatware_helper.rb` file like so:
|
138
109
|
|
139
|
-
|
110
|
+
```ruby
|
111
|
+
Flatware.configure do |conf|
|
112
|
+
conf.before_fork do
|
113
|
+
require 'rails_helper'
|
114
|
+
|
115
|
+
ActiveRecord::Base.connection.disconnect!
|
116
|
+
end
|
117
|
+
|
118
|
+
conf.after_fork do |test_env_number|
|
119
|
+
config = ActiveRecord::Base.connection_config
|
120
|
+
|
121
|
+
ActiveRecord::Base.establish_connection(
|
122
|
+
config.merge(
|
123
|
+
database: config.fetch(:database) + test_env_number.to_s
|
124
|
+
)
|
125
|
+
)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
```
|
129
|
+
Now when I run `bundle exec flatware rspec -r ./spec/flatware_helper` My app only boots once, rather than once per core.
|
140
130
|
|
141
131
|
## Design Goals
|
142
132
|
|
@@ -167,20 +157,10 @@ directory. CD there and `flatware` will be in your path so you can tinker away.
|
|
167
157
|
|
168
158
|
## How it works
|
169
159
|
|
170
|
-
Flatware relies on a message passing system to enable concurrency.
|
171
|
-
The main process declares a worker for each cpu in the computer. Each
|
172
|
-
worker forks from the main process and is then assigned a portion of the
|
173
|
-
test suite. As the worker runs the test suite it sends progress
|
174
|
-
messages to the main process. These messages are collected and when
|
175
|
-
the last worker is finished the main process provides a report on the
|
176
|
-
collected progress messages.
|
160
|
+
Flatware relies on a message passing system to enable concurrency. The main process forks a worker for each cpu in the computer. These workers are each given a chunk of the tests to run. The workers report back to the main process about their progress. The main process prints those progress messages. When the last worker is finished the main process prints the results.
|
177
161
|
|
178
162
|
## Resources
|
179
163
|
|
180
|
-
To learn more about the messaging system that Flatware uses, take a look at the
|
181
|
-
[excellent ZeroMQ guide][z].
|
182
|
-
|
183
|
-
[z]: http://zguide.zeromq.org/page:all
|
184
164
|
[a]: https://github.com/cucumber/aruba
|
185
165
|
|
186
166
|
## Contributing to Flatware
|
data/lib/flatware/rspec.rb
CHANGED
@@ -6,15 +6,16 @@ require 'flatware/rspec/cli'
|
|
6
6
|
|
7
7
|
module Flatware
|
8
8
|
module RSpec
|
9
|
-
require 'flatware/rspec/formatters/console'
|
10
9
|
require 'flatware/rspec/formatter'
|
11
10
|
require 'flatware/rspec/job_builder'
|
12
11
|
|
13
|
-
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def extract_jobs_from_args(args, workers:)
|
14
15
|
JobBuilder.new(args, workers: workers).jobs
|
15
|
-
|
16
|
+
end
|
16
17
|
|
17
|
-
def
|
18
|
+
def run(job, _options = {})
|
18
19
|
runner = ::RSpec::Core::Runner
|
19
20
|
def runner.trap_interrupt() end
|
20
21
|
|
@@ -1,28 +1,60 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'flatware/rspec/marshalable'
|
2
5
|
|
3
6
|
module Flatware
|
4
7
|
module RSpec
|
8
|
+
##
|
9
|
+
# Marshalable container for the run details from a worker.
|
10
|
+
# Can be added to other checkpoints to create a final run summary.
|
5
11
|
class Checkpoint
|
6
|
-
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
def_delegator :summary, :failures?
|
15
|
+
def_delegators :failures_notification, :fully_formatted_failed_examples, :failure_notifications
|
16
|
+
def_delegators :pending_notification, :fully_formatted_pending_examples, :pending_examples
|
17
|
+
|
18
|
+
EVENTS = %i[dump_profile dump_summary dump_pending dump_failures].freeze
|
19
|
+
|
20
|
+
attr_reader :events
|
21
|
+
|
22
|
+
def initialize(events = {})
|
23
|
+
@events = events
|
24
|
+
end
|
7
25
|
|
8
|
-
|
9
|
-
|
26
|
+
EVENTS.each do |event|
|
27
|
+
define_method(event) do |notification|
|
28
|
+
events[event] = Marshalable.for_event(event).from_notification(notification)
|
29
|
+
end
|
10
30
|
end
|
11
31
|
|
12
32
|
def +(other)
|
13
|
-
self.class.new
|
33
|
+
self.class.new(
|
34
|
+
events.merge(other.events) { |_, event, other_event| event + other_event }
|
35
|
+
)
|
14
36
|
end
|
15
37
|
|
16
38
|
def failures?
|
17
|
-
summary.
|
39
|
+
summary.failures?
|
18
40
|
end
|
19
41
|
|
20
|
-
def
|
21
|
-
|
42
|
+
def summary
|
43
|
+
events.fetch(:dump_summary)
|
44
|
+
end
|
45
|
+
|
46
|
+
def profile
|
47
|
+
events[:dump_profile]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def failures_notification
|
53
|
+
events.fetch(:dump_failures)
|
22
54
|
end
|
23
55
|
|
24
|
-
def
|
25
|
-
|
56
|
+
def pending_notification
|
57
|
+
events.fetch(:dump_pending)
|
26
58
|
end
|
27
59
|
end
|
28
60
|
end
|
data/lib/flatware/rspec/cli.rb
CHANGED
@@ -1,16 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'flatware/cli'
|
4
|
+
require 'flatware/rspec'
|
5
|
+
require 'flatware/rspec/formatters/console'
|
2
6
|
|
3
7
|
module Flatware
|
8
|
+
# rspec thor command
|
4
9
|
class CLI
|
5
10
|
worker_option
|
6
|
-
method_option
|
7
|
-
|
8
|
-
|
11
|
+
method_option(
|
12
|
+
'sink-endpoint',
|
13
|
+
type: :string,
|
14
|
+
default: 'drbunix:sink'
|
15
|
+
)
|
16
|
+
desc 'rspec [FLATWARE_OPTS]', 'parallelizes rspec'
|
9
17
|
def rspec(*rspec_args)
|
10
18
|
jobs = RSpec.extract_jobs_from_args rspec_args, workers: workers
|
19
|
+
formatter = Flatware::RSpec::Formatters::Console.new($stdout, $stderr)
|
11
20
|
Flatware.verbose = options[:log]
|
12
|
-
Worker.spawn count: workers, runner: RSpec,
|
13
|
-
start_sink
|
21
|
+
Worker.spawn count: workers, runner: RSpec, sink: options['sink-endpoint']
|
22
|
+
start_sink(jobs: jobs,
|
23
|
+
workers: workers,
|
24
|
+
formatter: formatter)
|
14
25
|
end
|
15
26
|
end
|
16
27
|
end
|
@@ -1,50 +1,58 @@
|
|
1
1
|
require 'flatware/rspec/checkpoint'
|
2
|
-
require 'flatware/rspec/summary'
|
3
2
|
require 'rspec/core/formatters/console_codes'
|
3
|
+
require 'forwardable'
|
4
4
|
|
5
5
|
module Flatware
|
6
6
|
module RSpec
|
7
7
|
ProgressMessage = Struct.new(:progress)
|
8
8
|
|
9
9
|
class Formatter
|
10
|
-
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
def_delegators :@checkpoint, *Checkpoint::EVENTS
|
13
|
+
|
14
|
+
attr_reader :output
|
11
15
|
|
12
16
|
def initialize(stdout)
|
13
17
|
@output = stdout
|
14
18
|
end
|
15
19
|
|
16
|
-
def example_passed(
|
20
|
+
def example_passed(_example)
|
17
21
|
send_progress :passed
|
18
22
|
end
|
19
23
|
|
20
|
-
def example_failed(
|
24
|
+
def example_failed(_example)
|
21
25
|
send_progress :failed
|
22
26
|
end
|
23
27
|
|
24
|
-
def example_pending(
|
28
|
+
def example_pending(_example)
|
25
29
|
send_progress :pending
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
@
|
30
|
-
end
|
31
|
-
|
32
|
-
def dump_failures(failure_notification)
|
33
|
-
@failure_notification = failure_notification
|
32
|
+
def start_dump(*)
|
33
|
+
@checkpoint = Checkpoint.new
|
34
34
|
end
|
35
35
|
|
36
36
|
def close(*)
|
37
|
-
Sink
|
38
|
-
@
|
37
|
+
Sink.client.checkpoint @checkpoint
|
38
|
+
@checkpoint = nil
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
43
|
def send_progress(status)
|
44
|
-
Sink
|
44
|
+
Sink.client.progress ProgressMessage.new status
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
::RSpec::Core::Formatters.register
|
48
|
+
::RSpec::Core::Formatters.register(
|
49
|
+
Formatter,
|
50
|
+
*Checkpoint::EVENTS,
|
51
|
+
:example_passed,
|
52
|
+
:example_failed,
|
53
|
+
:example_pending,
|
54
|
+
:start_dump,
|
55
|
+
:close
|
56
|
+
)
|
49
57
|
end
|
50
58
|
end
|
@@ -1,33 +1,69 @@
|
|
1
|
-
|
2
|
-
class Console
|
3
|
-
attr_reader :formatter
|
4
|
-
|
5
|
-
def initialize(out, err)
|
6
|
-
::RSpec::configuration.tty = true
|
7
|
-
::RSpec::configuration.color = true
|
8
|
-
@formatter = ::RSpec::Core::Formatters::ProgressFormatter.new(out)
|
9
|
-
end
|
1
|
+
require 'rspec/core'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
|
3
|
+
module Flatware
|
4
|
+
module RSpec
|
5
|
+
module Formatters
|
6
|
+
class Console
|
7
|
+
attr_reader :progress_formatter, :profile_formatter
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
9
|
+
def initialize(out, _err)
|
10
|
+
::RSpec.configuration.tty = true
|
11
|
+
::RSpec.configuration.color = true
|
12
|
+
@progress_formatter = ::RSpec::Core::Formatters::ProgressFormatter.new(out)
|
13
|
+
@profile_formatter = ::RSpec::Core::Formatters::ProfileFormatter.new(out)
|
14
|
+
end
|
15
|
+
|
16
|
+
def progress(result)
|
17
|
+
progress_formatter.public_send(message_for(result), nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
def summarize(checkpoints)
|
21
|
+
return if checkpoints.empty?
|
22
|
+
|
23
|
+
result = checkpoints.reduce :+
|
24
|
+
|
25
|
+
progress_formatter.dump_failures(result)
|
26
|
+
progress_formatter.dump_summary(result.summary)
|
27
|
+
profile_formatter.dump_profile(result.profile) if result.profile
|
28
|
+
progress_formatter.dump_pending(result) if result.pending_examples.any?
|
29
|
+
end
|
22
30
|
|
23
|
-
|
31
|
+
def summarize_remaining(remaining)
|
32
|
+
progress_formatter.output.puts(colorizer.wrap(<<~MESSAGE, :detail))
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
The following specs weren't run:
|
35
|
+
|
36
|
+
#{spec_list(remaining)}
|
37
|
+
|
38
|
+
MESSAGE
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def spec_list(remaining)
|
44
|
+
remaining
|
45
|
+
.flat_map(&:id).sort.each_with_index
|
46
|
+
.map do |example, index|
|
47
|
+
format(
|
48
|
+
'%<index>4d) %<example>s',
|
49
|
+
index: index.next,
|
50
|
+
example: example
|
51
|
+
)
|
52
|
+
end.join("\n")
|
53
|
+
end
|
54
|
+
|
55
|
+
def colorizer
|
56
|
+
::RSpec::Core::Formatters::ConsoleCodes
|
57
|
+
end
|
58
|
+
|
59
|
+
def message_for(result)
|
60
|
+
{
|
61
|
+
passed: :example_passed,
|
62
|
+
failed: :example_failed,
|
63
|
+
pending: :example_pending
|
64
|
+
}.fetch result.progress
|
65
|
+
end
|
66
|
+
end
|
31
67
|
end
|
32
68
|
end
|
33
69
|
end
|
@@ -28,36 +28,39 @@ module Flatware
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def jobs
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
if (time = seconds_per_file[file])
|
44
|
-
[timed.push([file, time]), untimed]
|
45
|
-
else
|
46
|
-
[timed, untimed.push(file)]
|
47
|
-
end
|
48
|
-
end
|
31
|
+
timed_files, untimed_files = timed_and_untimed_files(
|
32
|
+
sum_seconds(load_persisted_example_statuses)
|
33
|
+
)
|
34
|
+
|
35
|
+
balance_jobs(
|
36
|
+
bucket_count: [files_to_run.size, workers].min,
|
37
|
+
timed_files: timed_files,
|
38
|
+
untimed_files: untimed_files
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
49
43
|
|
44
|
+
def balance_jobs(bucket_count:, timed_files:, untimed_files:)
|
50
45
|
balance_by(bucket_count, timed_files, &:last)
|
51
46
|
.map { |bucket| bucket.map(&:first) }
|
52
47
|
.zip(
|
53
48
|
round_robin(bucket_count, untimed_files)
|
54
49
|
).map(&:flatten)
|
55
|
-
.map
|
56
|
-
Job.new(files, args)
|
57
|
-
end
|
50
|
+
.map { |files| Job.new(files, args) }
|
58
51
|
end
|
59
52
|
|
60
|
-
|
53
|
+
def timed_and_untimed_files(seconds_per_file)
|
54
|
+
files_to_run
|
55
|
+
.map(&method(:normalize_path))
|
56
|
+
.reduce([[], []]) do |(timed, untimed), file|
|
57
|
+
if (time = seconds_per_file[file])
|
58
|
+
[timed + [[file, time]], untimed]
|
59
|
+
else
|
60
|
+
[timed, untimed + [file]]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
61
64
|
|
62
65
|
def normalize_path(path)
|
63
66
|
::RSpec::Core::Metadata.relative_path(File.expand_path(path))
|
@@ -69,22 +72,26 @@ module Flatware
|
|
69
72
|
)
|
70
73
|
end
|
71
74
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
+
def sum_seconds(statuses)
|
76
|
+
statuses.select(&passing)
|
77
|
+
.map { |example| parse_example(**example) }
|
78
|
+
.reduce({}) do |times, example|
|
79
|
+
times.merge(
|
80
|
+
example.fetch(:file_name) => example.fetch(:seconds)
|
81
|
+
) do |_, old = 0, new|
|
82
|
+
old + new
|
83
|
+
end
|
75
84
|
end
|
76
85
|
end
|
77
86
|
|
78
87
|
def passing
|
79
|
-
->(
|
88
|
+
->(example) { example.fetch(:status) =~ /pass/i }
|
80
89
|
end
|
81
90
|
|
82
|
-
def parse_example
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
{ seconds: seconds, file_name: file_name }
|
87
|
-
end
|
91
|
+
def parse_example(example_id:, run_time:, **)
|
92
|
+
seconds = run_time.match(/\d+(\.\d+)?/).to_s.to_f
|
93
|
+
file_name = ::RSpec::Core::Example.parse_id(example_id).first
|
94
|
+
{ seconds: seconds, file_name: file_name }
|
88
95
|
end
|
89
96
|
|
90
97
|
def round_robin(count, items)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Flatware
|
2
|
+
module RSpec
|
3
|
+
module Marshalable
|
4
|
+
require 'flatware/rspec/marshalable/examples_notification'
|
5
|
+
require 'flatware/rspec/marshalable/profile_notification'
|
6
|
+
require 'flatware/rspec/marshalable/summary_notification'
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def for_event(event)
|
11
|
+
{
|
12
|
+
dump_pending: ExamplesNotification,
|
13
|
+
dump_failures: ExamplesNotification,
|
14
|
+
dump_profile: ProfileNotification,
|
15
|
+
dump_summary: SummaryNotification
|
16
|
+
}.fetch(event)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Flatware
|
2
|
+
module RSpec
|
3
|
+
module Marshalable
|
4
|
+
##
|
5
|
+
# a subset of the rspec example interface that can traverse drb
|
6
|
+
Example = Struct.new(
|
7
|
+
*%i[
|
8
|
+
execution_result
|
9
|
+
full_description
|
10
|
+
location
|
11
|
+
location_rerun_argument
|
12
|
+
]
|
13
|
+
) do
|
14
|
+
def initialize(rspec_example)
|
15
|
+
super(*members.map do |attribute|
|
16
|
+
rspec_example.public_send(attribute)
|
17
|
+
end)
|
18
|
+
|
19
|
+
@metadata = rspec_example.metadata.slice(:extra_failure_lines, :shared_group_inclusion_backtrace)
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :metadata
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rspec/core'
|
2
|
+
require 'flatware/rspec/marshalable/example'
|
3
|
+
|
4
|
+
module Flatware
|
5
|
+
module RSpec
|
6
|
+
module Marshalable
|
7
|
+
class ExamplesNotification < ::RSpec::Core::Notifications::ExamplesNotification
|
8
|
+
Reporter = Struct.new(:examples, :failed_examples, :pending_examples) do
|
9
|
+
def self.from_rspec(reporter)
|
10
|
+
new(*members.map { |member| reporter.public_send(member).map(&Example.method(:new)) })
|
11
|
+
end
|
12
|
+
|
13
|
+
def +(other)
|
14
|
+
self.class.new(*zip(other).map { |a, b| a + b })
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :reporter
|
19
|
+
|
20
|
+
def self.from_notification(rspec_notification)
|
21
|
+
new Reporter.from_rspec(rspec_notification.instance_variable_get(:@reporter))
|
22
|
+
end
|
23
|
+
|
24
|
+
def +(other)
|
25
|
+
self.class.new reporter + other.reporter
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'flatware/rspec/marshalable/example'
|
2
|
+
require 'flatware/rspec/marshalable/example_group'
|
3
|
+
|
4
|
+
module Flatware
|
5
|
+
module RSpec
|
6
|
+
module Marshalable
|
7
|
+
class ProfileNotification < ::RSpec::Core::Notifications::ProfileNotification
|
8
|
+
attr_reader :example_groups
|
9
|
+
|
10
|
+
def +(other)
|
11
|
+
self.class.new(
|
12
|
+
duration + other.duration,
|
13
|
+
examples + other.examples,
|
14
|
+
number_of_examples,
|
15
|
+
example_groups.merge(other.example_groups)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.from_notification(rspec_notification)
|
20
|
+
new(
|
21
|
+
rspec_notification.duration,
|
22
|
+
rspec_notification.examples.map(&Example.method(:new)),
|
23
|
+
rspec_notification.number_of_examples,
|
24
|
+
rspec_notification.instance_variable_get(:@example_groups).transform_keys(&ExampleGroup.method(:new))
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rspec/core/notifications'
|
2
|
+
require 'flatware/rspec/marshalable/example'
|
3
|
+
|
4
|
+
module Flatware
|
5
|
+
module RSpec
|
6
|
+
module Marshalable
|
7
|
+
class SummaryNotification < ::RSpec::Core::Notifications::SummaryNotification
|
8
|
+
def +(other)
|
9
|
+
self.class.new(*zip(other).map { |a, b| a + b })
|
10
|
+
end
|
11
|
+
|
12
|
+
def failures?
|
13
|
+
[failure_count, errors_outside_of_examples_count].any?(&:positive?)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.from_notification(summary)
|
17
|
+
serialized_examples = [
|
18
|
+
summary.examples,
|
19
|
+
summary.failed_examples,
|
20
|
+
summary.pending_examples
|
21
|
+
].map do |examples|
|
22
|
+
examples.map(&Example.method(:new))
|
23
|
+
end
|
24
|
+
|
25
|
+
new(summary.duration, *serialized_examples, *summary.to_a[4..])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flatware-rspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Dunn
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: flatware
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.0.0.rc1
|
20
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: 2.0.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,33 +52,39 @@ files:
|
|
52
52
|
- lib/flatware/rspec.rb
|
53
53
|
- lib/flatware/rspec/checkpoint.rb
|
54
54
|
- lib/flatware/rspec/cli.rb
|
55
|
-
- lib/flatware/rspec/example_notification.rb
|
56
|
-
- lib/flatware/rspec/examples_notification.rb
|
57
55
|
- lib/flatware/rspec/formatter.rb
|
58
56
|
- lib/flatware/rspec/formatters/console.rb
|
59
57
|
- lib/flatware/rspec/job_builder.rb
|
60
|
-
- lib/flatware/rspec/
|
58
|
+
- lib/flatware/rspec/marshalable.rb
|
59
|
+
- lib/flatware/rspec/marshalable/example.rb
|
60
|
+
- lib/flatware/rspec/marshalable/example_group.rb
|
61
|
+
- lib/flatware/rspec/marshalable/examples_notification.rb
|
62
|
+
- lib/flatware/rspec/marshalable/profile_notification.rb
|
63
|
+
- lib/flatware/rspec/marshalable/summary_notification.rb
|
61
64
|
homepage: http://github.com/briandunn/flatware
|
62
65
|
licenses:
|
63
66
|
- MIT
|
64
67
|
metadata: {}
|
65
|
-
post_install_message:
|
68
|
+
post_install_message:
|
66
69
|
rdoc_options: []
|
67
70
|
require_paths:
|
68
71
|
- lib
|
69
72
|
required_ruby_version: !ruby/object:Gem::Requirement
|
70
73
|
requirements:
|
71
|
-
- - "
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.6'
|
77
|
+
- - "<"
|
72
78
|
- !ruby/object:Gem::Version
|
73
|
-
version: '
|
79
|
+
version: '3.1'
|
74
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
81
|
requirements:
|
76
|
-
- - "
|
82
|
+
- - ">"
|
77
83
|
- !ruby/object:Gem::Version
|
78
|
-
version:
|
84
|
+
version: 1.3.1
|
79
85
|
requirements: []
|
80
|
-
rubygems_version: 3.
|
81
|
-
signing_key:
|
86
|
+
rubygems_version: 3.2.3
|
87
|
+
signing_key:
|
82
88
|
specification_version: 4
|
83
89
|
summary: A distributed rspec runner
|
84
90
|
test_files: []
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'rspec/core/formatters/console_codes'
|
2
|
-
|
3
|
-
module Flatware
|
4
|
-
module RSpec
|
5
|
-
class ExampleNotification
|
6
|
-
attr_reader :formatted
|
7
|
-
def initialize(notification)
|
8
|
-
@formatted = notification.fully_formatted '!', default_colorizer
|
9
|
-
end
|
10
|
-
|
11
|
-
def fully_formatted(i, _=nil)
|
12
|
-
formatted.sub '!', i.to_s
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
def default_colorizer
|
17
|
-
::RSpec::Core::Formatters::ConsoleCodes
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'flatware/rspec/example_notification'
|
2
|
-
module Flatware
|
3
|
-
module RSpec
|
4
|
-
class ExamplesNotification
|
5
|
-
attr_reader :failure_notifications
|
6
|
-
|
7
|
-
def initialize(failure_notifications)
|
8
|
-
@failure_notifications = failure_notifications.map(&ExampleNotification.method(:new))
|
9
|
-
end
|
10
|
-
|
11
|
-
def +(other)
|
12
|
-
self.class.new failure_notifications + other.failure_notifications
|
13
|
-
end
|
14
|
-
|
15
|
-
def fully_formatted_failed_examples(*)
|
16
|
-
formatted = "\n\nFailures:\n"
|
17
|
-
failure_notifications.each_with_index do |failure, index|
|
18
|
-
formatted << failure.fully_formatted(index.next)
|
19
|
-
end
|
20
|
-
formatted
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'rspec/core/notifications'
|
2
|
-
module Flatware
|
3
|
-
module RSpec
|
4
|
-
class Example
|
5
|
-
attr_reader :location_rerun_argument, :full_description
|
6
|
-
def initialize(rspec_example)
|
7
|
-
@full_description = rspec_example.full_description
|
8
|
-
@location_rerun_argument = rspec_example.location_rerun_argument
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class Summary < ::RSpec::Core::Notifications::SummaryNotification
|
13
|
-
def +(other)
|
14
|
-
self.class.new(*zip(other).map {|a,b| a + b})
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.from_notification(summary)
|
18
|
-
serialized_examples = [summary.examples, summary.failed_examples, summary.pending_examples].map do |examples|
|
19
|
-
examples.map(&Example.method(:new))
|
20
|
-
end
|
21
|
-
|
22
|
-
new summary.duration, *serialized_examples, *summary.to_a[4..-1]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|