paraspec 0.0.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.
- checksums.yaml +7 -0
- data/LICENSE +23 -0
- data/README.md +97 -0
- data/bin/paraspec +53 -0
- data/lib/paraspec.rb +21 -0
- data/lib/paraspec/drb_helpers.rb +65 -0
- data/lib/paraspec/http_client.rb +43 -0
- data/lib/paraspec/http_server.rb +24 -0
- data/lib/paraspec/ipc.rb +11 -0
- data/lib/paraspec/logger.rb +44 -0
- data/lib/paraspec/master.rb +219 -0
- data/lib/paraspec/master_runner.rb +7 -0
- data/lib/paraspec/msgpack_client.rb +53 -0
- data/lib/paraspec/msgpack_helpers.rb +46 -0
- data/lib/paraspec/msgpack_server.rb +58 -0
- data/lib/paraspec/process_helpers.rb +22 -0
- data/lib/paraspec/rspec_facade.rb +38 -0
- data/lib/paraspec/rspec_patches.rb +23 -0
- data/lib/paraspec/supervisor.rb +127 -0
- data/lib/paraspec/version.rb +3 -0
- data/lib/paraspec/worker.rb +70 -0
- data/lib/paraspec/worker_formatter.rb +82 -0
- data/lib/paraspec/worker_runner.rb +67 -0
- metadata +123 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rspec/core'
|
2
|
+
|
3
|
+
module Paraspec
|
4
|
+
class WorkerFormatter
|
5
|
+
RSpec::Core::Formatters.register self,
|
6
|
+
#:start,
|
7
|
+
:example_group_started,
|
8
|
+
:example_started,
|
9
|
+
:example_passed,
|
10
|
+
:example_failed,
|
11
|
+
:example_pending,
|
12
|
+
:message,
|
13
|
+
#:stop,
|
14
|
+
:start_dump,
|
15
|
+
:dump_pending,
|
16
|
+
:dump_failures,
|
17
|
+
:dump_summary,
|
18
|
+
:seed,
|
19
|
+
:close
|
20
|
+
|
21
|
+
def initialize(output)
|
22
|
+
@master_client = output.master_client
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(notification)
|
26
|
+
# Worker formatter receives start notification for each example
|
27
|
+
# that it receives from supervisor.
|
28
|
+
# The start notification contains number of examples to be executed,
|
29
|
+
# and the load time.
|
30
|
+
# The number of examples isn't useful because this is a subset of
|
31
|
+
# all of the examples to be run, and we can't wait to receive
|
32
|
+
# start notifications from all workers in the master thus
|
33
|
+
# start notifications are not aggregatable.
|
34
|
+
# Loading time is something that master can figure out on its own.
|
35
|
+
# Therefore we do not forward start notifications to master.
|
36
|
+
# At the same time master must create and send start notifications
|
37
|
+
# to its own formatters, for example the junit formatter
|
38
|
+
# requires a start notification for the summary report to work.
|
39
|
+
end
|
40
|
+
|
41
|
+
def stop(notification)
|
42
|
+
# Stop notification doesn't carry any new information, thus
|
43
|
+
# master directly invokes reporter.stop from dump_summary.
|
44
|
+
end
|
45
|
+
|
46
|
+
def dump_summary(notification)
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing(m, args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def example_started(notification)
|
53
|
+
spec = {
|
54
|
+
file_path: notification.example.metadata[:file_path],
|
55
|
+
scoped_id: notification.example.metadata[:scoped_id],
|
56
|
+
}
|
57
|
+
@master_client.request('notify-example-started', spec: spec)
|
58
|
+
end
|
59
|
+
|
60
|
+
def example_passed(notification)
|
61
|
+
example_notification(notification)
|
62
|
+
end
|
63
|
+
|
64
|
+
def example_notification(notification)
|
65
|
+
spec = {
|
66
|
+
file_path: notification.example.metadata[:file_path],
|
67
|
+
scoped_id: notification.example.metadata[:scoped_id],
|
68
|
+
}
|
69
|
+
execution_result = notification.example.execution_result
|
70
|
+
@master_client.request('example-passed',
|
71
|
+
spec: spec, result: execution_result)
|
72
|
+
end
|
73
|
+
|
74
|
+
def example_failed(notification)
|
75
|
+
example_notification(notification)
|
76
|
+
end
|
77
|
+
|
78
|
+
def example_pending(notification)
|
79
|
+
example_notification(notification)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Paraspec
|
2
|
+
# An RSpec test runner - in a worker process.
|
3
|
+
# This runner collects results and output and forwards them to the
|
4
|
+
# master process via DRb.
|
5
|
+
class WorkerRunner
|
6
|
+
def initialize(options={})
|
7
|
+
@master_client = options[:master_client]
|
8
|
+
|
9
|
+
# TODO capture stdout & stderr
|
10
|
+
class << STDERR
|
11
|
+
def master_client
|
12
|
+
@master_client
|
13
|
+
end
|
14
|
+
end
|
15
|
+
STDERR.send(:instance_variable_set, '@master_client', @master_client)
|
16
|
+
runner.setup(STDOUT, STDERR)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run(spec)
|
20
|
+
if RSpecFacade.all_example_groups.count == 0
|
21
|
+
raise "No example groups loaded"
|
22
|
+
end
|
23
|
+
group = RSpecFacade.all_example_groups.detect do |g|
|
24
|
+
g.metadata[:file_path] == spec[:file_path] &&
|
25
|
+
g.metadata[:scoped_id] == spec[:scoped_id]
|
26
|
+
end
|
27
|
+
unless group
|
28
|
+
puts "No example group for #{spec.inspect}, #{RSpecFacade.all_example_groups.count} total groups"
|
29
|
+
#byebug
|
30
|
+
raise "No example group for #{spec.inspect}"
|
31
|
+
end
|
32
|
+
examples = group.examples
|
33
|
+
#Paraspec.logger.debug_state("Spec #{spec}: #{examples.length} examples")
|
34
|
+
return if examples.empty?
|
35
|
+
ids = examples.map { |e| e.metadata[:scoped_id] }
|
36
|
+
RSpec.configuration.send(:instance_variable_set, '@filter_manager', RSpec::Core::FilterManager.new)
|
37
|
+
RSpec.configuration.filter_manager.add_ids(spec[:file_path], ids)
|
38
|
+
RSpec.world.filter_examples
|
39
|
+
examples = RSpec.configuration.filter_manager.prune(examples)
|
40
|
+
return if examples.empty?
|
41
|
+
# It is important to run the entire world here because if
|
42
|
+
# a particular example group is run, before/after :all hooks
|
43
|
+
# aren't always run
|
44
|
+
RSpec.world.ordered_example_groups.each do |group|
|
45
|
+
group.reset_memoized
|
46
|
+
end
|
47
|
+
# Hack to not run examples from each group each time I want to run
|
48
|
+
# a single example. It seems that rspec performs filtering by file
|
49
|
+
# at one time and by expressions/scoped id at a different time,
|
50
|
+
# because simply requesting filtering by scoped id makes rspec
|
51
|
+
# include examples from all other files (it also mutates the filters
|
52
|
+
# when querying them for example groups... ugh)
|
53
|
+
run_example_groups = RSpec.world.ordered_example_groups.select do |c_group|
|
54
|
+
c_group.metadata[:file_path] == spec[:file_path]
|
55
|
+
end
|
56
|
+
runner.run_specs(run_example_groups)
|
57
|
+
end
|
58
|
+
|
59
|
+
private def runner
|
60
|
+
@runner ||= begin
|
61
|
+
options = RSpec::Core::ConfigurationOptions.new(ARGV)
|
62
|
+
options.options[:formatters] = [['Paraspec::WorkerFormatter']]
|
63
|
+
RSpec::Core::Runner.new(options)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paraspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Oleg Pudeyev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec-core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.7.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.7.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: childprocess
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.9.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: hashie
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.5.7
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.5.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: msgpack
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.2.4
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.2.4
|
69
|
+
description: Parallel RSpec runner
|
70
|
+
email: oleg@olegp.name
|
71
|
+
executables:
|
72
|
+
- paraspec
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- LICENSE
|
77
|
+
- README.md
|
78
|
+
- bin/paraspec
|
79
|
+
- lib/paraspec.rb
|
80
|
+
- lib/paraspec/drb_helpers.rb
|
81
|
+
- lib/paraspec/http_client.rb
|
82
|
+
- lib/paraspec/http_server.rb
|
83
|
+
- lib/paraspec/ipc.rb
|
84
|
+
- lib/paraspec/logger.rb
|
85
|
+
- lib/paraspec/master.rb
|
86
|
+
- lib/paraspec/master_runner.rb
|
87
|
+
- lib/paraspec/msgpack_client.rb
|
88
|
+
- lib/paraspec/msgpack_helpers.rb
|
89
|
+
- lib/paraspec/msgpack_server.rb
|
90
|
+
- lib/paraspec/process_helpers.rb
|
91
|
+
- lib/paraspec/rspec_facade.rb
|
92
|
+
- lib/paraspec/rspec_patches.rb
|
93
|
+
- lib/paraspec/supervisor.rb
|
94
|
+
- lib/paraspec/version.rb
|
95
|
+
- lib/paraspec/worker.rb
|
96
|
+
- lib/paraspec/worker_formatter.rb
|
97
|
+
- lib/paraspec/worker_runner.rb
|
98
|
+
homepage: https://github.com/paraspec/paraspec
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options:
|
104
|
+
- "--charset=UTF-8"
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 1.9.3
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.7.3
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: paraspec-0.0.1
|
123
|
+
test_files: []
|