flatware 0.0.4 → 0.1.0
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/README.rdoc +4 -1
- data/lib/flatware.rb +39 -4
- data/lib/flatware/checkpoint.rb +2 -1
- data/lib/flatware/cli.rb +1 -1
- data/lib/flatware/cucumber/formatter.rb +6 -1
- data/lib/flatware/dispatcher.rb +4 -6
- data/lib/flatware/fireable.rb +35 -7
- data/lib/flatware/processor_info.rb +20 -0
- data/lib/flatware/scenario_decorator.rb +24 -0
- data/lib/flatware/scenario_result.rb +4 -2
- data/lib/flatware/sink.rb +10 -14
- data/lib/flatware/summary.rb +11 -0
- data/lib/flatware/version.rb +1 -1
- data/lib/flatware/worker.rb +2 -5
- metadata +22 -20
data/README.rdoc
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
= Flatware
|
2
2
|
|
3
|
-
|
3
|
+
{<img src="https://travis-ci.org/briandunn/flatware.png" />}[https://travis-ci.org/briandunn/flatware]
|
4
|
+
{<img src="https://codeclimate.com/badge.png" />}[https://codeclimate.com/github/briandunn/flatware]
|
5
|
+
|
6
|
+
Flatware is a distributed cucumber runner.
|
4
7
|
|
5
8
|
== Requirements
|
6
9
|
|
data/lib/flatware.rb
CHANGED
@@ -1,29 +1,42 @@
|
|
1
|
-
require '
|
1
|
+
require 'forwardable'
|
2
|
+
require 'ffi-rzmq'
|
2
3
|
|
3
4
|
module Flatware
|
4
5
|
autoload :CLI, 'flatware/cli'
|
5
6
|
autoload :Cucumber, 'flatware/cucumber'
|
6
7
|
autoload :Dispatcher, 'flatware/dispatcher'
|
7
8
|
autoload :Fireable, 'flatware/fireable'
|
9
|
+
autoload :ProcessorInfo, 'flatware/processor_info'
|
8
10
|
autoload :Result, 'flatware/result'
|
9
11
|
autoload :ScenarioResult, 'flatware/scenario_result'
|
10
12
|
autoload :Sink, 'flatware/sink'
|
11
13
|
autoload :StepResult, 'flatware/step_result'
|
12
14
|
autoload :Summary, 'flatware/summary'
|
13
15
|
autoload :Worker, 'flatware/worker'
|
16
|
+
autoload :ScenarioDecorator, 'flatware/scenario_decorator'
|
17
|
+
|
18
|
+
Error = Class.new StandardError
|
14
19
|
|
15
20
|
Job = Struct.new :id, :args
|
16
21
|
|
17
22
|
extend self
|
18
|
-
def socket(
|
19
|
-
context.socket(
|
23
|
+
def socket(type, options={})
|
24
|
+
Socket.new(context.socket(type)).tap do |socket|
|
20
25
|
sockets.push socket
|
26
|
+
if port = options[:connect]
|
27
|
+
socket.connect port
|
28
|
+
end
|
29
|
+
if port = options[:bind]
|
30
|
+
socket.bind port
|
31
|
+
end
|
32
|
+
#FIXME: figure out how to do this without waiting
|
33
|
+
sleep 0.05
|
21
34
|
end
|
22
35
|
end
|
23
36
|
|
24
37
|
def close
|
25
38
|
sockets.each &:close
|
26
|
-
context.
|
39
|
+
context.terminate
|
27
40
|
@context = nil
|
28
41
|
end
|
29
42
|
|
@@ -47,4 +60,26 @@ module Flatware
|
|
47
60
|
def sockets
|
48
61
|
@sockets ||= []
|
49
62
|
end
|
63
|
+
|
64
|
+
Socket = Struct.new :s do
|
65
|
+
extend Forwardable
|
66
|
+
def_delegators :s, :bind, :connect, :setsockopt
|
67
|
+
def send(message)
|
68
|
+
result = s.send_string(Marshal.dump(message))
|
69
|
+
raise Error, ZMQ::Util.error_string, caller unless result == 0
|
70
|
+
message
|
71
|
+
end
|
72
|
+
|
73
|
+
def close
|
74
|
+
s.setsockopt(ZMQ::LINGER, 1)
|
75
|
+
s.close
|
76
|
+
end
|
77
|
+
|
78
|
+
def recv
|
79
|
+
message = ''
|
80
|
+
result = s.recv_string(message)
|
81
|
+
raise Error, ZMQ::Util.error_string, caller unless result == 0
|
82
|
+
Marshal.load message
|
83
|
+
end
|
84
|
+
end
|
50
85
|
end
|
data/lib/flatware/checkpoint.rb
CHANGED
data/lib/flatware/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'cucumber/formatter/console'
|
2
2
|
require 'flatware/checkpoint'
|
3
|
+
require 'flatware/scenario_decorator'
|
3
4
|
module Flatware
|
4
5
|
module Cucumber
|
5
6
|
class Formatter
|
@@ -34,7 +35,7 @@ module Flatware
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def checkpoint
|
37
|
-
Checkpoint.new(step_mother.steps - @ran_steps, step_mother.scenarios - @ran_scenarios).tap do
|
38
|
+
Checkpoint.new(step_mother.steps - @ran_steps, decorate_scenarios(step_mother.scenarios - @ran_scenarios)).tap do
|
38
39
|
snapshot
|
39
40
|
end
|
40
41
|
end
|
@@ -45,6 +46,10 @@ module Flatware
|
|
45
46
|
@ran_steps = step_mother.steps.dup
|
46
47
|
@ran_scenarios = step_mother.scenarios.dup
|
47
48
|
end
|
49
|
+
|
50
|
+
def decorate_scenarios(scenarios)
|
51
|
+
scenarios.map { |scenario| ScenarioDecorator.new(scenario) }
|
52
|
+
end
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
data/lib/flatware/dispatcher.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Flatware
|
2
2
|
class Dispatcher
|
3
|
-
|
3
|
+
PORT = 'ipc://dispatch'
|
4
4
|
|
5
5
|
def self.start(jobs=Cucumber.jobs)
|
6
6
|
new(jobs).dispatch!
|
@@ -11,10 +11,10 @@ module Flatware
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def dispatch!
|
14
|
-
return
|
14
|
+
return if jobs.empty?
|
15
15
|
fireable.until_fired dispatch do |request|
|
16
16
|
if job = jobs.pop
|
17
|
-
dispatch.send
|
17
|
+
dispatch.send job
|
18
18
|
else
|
19
19
|
dispatch.send 'seppuku'
|
20
20
|
end
|
@@ -30,9 +30,7 @@ module Flatware
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def dispatch
|
33
|
-
@dispatch ||= Flatware.socket
|
34
|
-
socket.bind DISPATCH_PORT
|
35
|
-
end
|
33
|
+
@dispatch ||= Flatware.socket ZMQ::REP, bind: PORT
|
36
34
|
end
|
37
35
|
end
|
38
36
|
end
|
data/lib/flatware/fireable.rb
CHANGED
@@ -1,22 +1,50 @@
|
|
1
1
|
module Flatware
|
2
2
|
class Fireable
|
3
|
+
PORT = 'ipc://die'
|
4
|
+
|
5
|
+
def self.bind
|
6
|
+
@kill = Flatware.socket(ZMQ::PUB, bind: PORT)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.kill
|
10
|
+
@kill.send 'seppuku'
|
11
|
+
end
|
12
|
+
|
3
13
|
def initialize
|
4
|
-
@die = Flatware.socket(ZMQ::SUB).tap do |die|
|
5
|
-
die.connect 'ipc://die'
|
14
|
+
@die = Flatware.socket(ZMQ::SUB, connect: PORT).tap do |die|
|
6
15
|
die.setsockopt ZMQ::SUBSCRIBE, ''
|
7
16
|
end
|
8
17
|
end
|
9
18
|
|
10
19
|
attr_reader :die
|
11
20
|
|
12
|
-
def until_fired(
|
13
|
-
|
14
|
-
|
15
|
-
break if
|
16
|
-
|
21
|
+
def until_fired(socket, &block)
|
22
|
+
poller = Poller.new socket, die
|
23
|
+
poller.each do |message|
|
24
|
+
break if message == 'seppuku'
|
25
|
+
block.call message
|
17
26
|
end
|
18
27
|
ensure
|
19
28
|
Flatware.close
|
20
29
|
end
|
21
30
|
end
|
31
|
+
|
32
|
+
class Poller
|
33
|
+
attr_reader :sockets
|
34
|
+
def initialize(*sockets)
|
35
|
+
@sockets = sockets
|
36
|
+
end
|
37
|
+
|
38
|
+
def each(&block)
|
39
|
+
poller = ZMQ::Poller.new
|
40
|
+
for socket in sockets
|
41
|
+
poller.register_readable socket.s
|
42
|
+
end
|
43
|
+
while poller.poll > 0
|
44
|
+
poller.readables.each do |s|
|
45
|
+
block.call Socket.new(s).recv
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
22
50
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Flatware
|
2
|
+
class ProcessorInfo
|
3
|
+
def count
|
4
|
+
case operating_system
|
5
|
+
when 'Darwin'
|
6
|
+
`hostinfo`.match(/^(?<processors>\d+) processors are logically available\.$/)[:processors].to_i
|
7
|
+
when 'Linux'
|
8
|
+
`grep --count '^processor' /proc/cpuinfo`.to_i
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def operating_system
|
13
|
+
`uname`.chomp
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.count
|
17
|
+
new.count
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Flatware
|
2
|
+
class ScenarioDecorator
|
3
|
+
attr_reader :status
|
4
|
+
|
5
|
+
def initialize(scenario)
|
6
|
+
@scenario, @status = scenario, scenario.status
|
7
|
+
@scenario = scenario.scenario_outline if example_row?
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
@scenario.name
|
12
|
+
end
|
13
|
+
|
14
|
+
def file_colon_line
|
15
|
+
@scenario.file_colon_line
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def example_row?
|
21
|
+
@scenario.respond_to? :scenario_outline
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module Flatware
|
2
2
|
class ScenarioResult
|
3
|
-
attr_reader :status
|
4
|
-
def initialize(status)
|
3
|
+
attr_reader :status, :file_colon_line, :name
|
4
|
+
def initialize(status, file_colon_line, name)
|
5
5
|
@status = status
|
6
|
+
@file_colon_line = file_colon_line
|
7
|
+
@name = name
|
6
8
|
end
|
7
9
|
|
8
10
|
def passed?
|
data/lib/flatware/sink.rb
CHANGED
@@ -2,9 +2,10 @@ require 'flatware'
|
|
2
2
|
require 'flatware/cucumber/formatter'
|
3
3
|
module Flatware
|
4
4
|
class Sink
|
5
|
+
PORT = 'ipc://sink'
|
5
6
|
class << self
|
6
7
|
def push(message)
|
7
|
-
client.push
|
8
|
+
client.push message
|
8
9
|
end
|
9
10
|
|
10
11
|
def finished(job)
|
@@ -29,6 +30,7 @@ module Flatware
|
|
29
30
|
trap 'INT' do
|
30
31
|
summarize
|
31
32
|
summarize_remaining
|
33
|
+
exit 1
|
32
34
|
end
|
33
35
|
|
34
36
|
before_firing { listen }
|
@@ -38,7 +40,7 @@ module Flatware
|
|
38
40
|
def listen
|
39
41
|
until done?
|
40
42
|
message = socket.recv
|
41
|
-
case (result =
|
43
|
+
case (result = message)
|
42
44
|
when Result
|
43
45
|
print result.progress
|
44
46
|
when Checkpoint
|
@@ -47,11 +49,11 @@ module Flatware
|
|
47
49
|
completed_jobs << result
|
48
50
|
log "COMPLETED SCENARIO"
|
49
51
|
else
|
50
|
-
log "i don't know that message, bro."
|
52
|
+
log "i don't know that message, bro.", message
|
51
53
|
end
|
52
54
|
end
|
53
55
|
summarize
|
54
|
-
rescue
|
56
|
+
rescue Error => e
|
55
57
|
raise unless e.message == "Interrupted system call"
|
56
58
|
end
|
57
59
|
|
@@ -87,11 +89,9 @@ module Flatware
|
|
87
89
|
end
|
88
90
|
|
89
91
|
def before_firing(&block)
|
90
|
-
|
91
|
-
socket.bind 'ipc://die'
|
92
|
-
end
|
92
|
+
Flatware::Fireable::bind
|
93
93
|
block.call
|
94
|
-
|
94
|
+
Flatware::Fireable::kill
|
95
95
|
end
|
96
96
|
|
97
97
|
def checkpoints
|
@@ -116,9 +116,7 @@ module Flatware
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def socket
|
119
|
-
@socket ||= Flatware.socket(ZMQ::PULL
|
120
|
-
socket.bind 'ipc://sink'
|
121
|
-
end
|
119
|
+
@socket ||= Flatware.socket(ZMQ::PULL, bind: PORT)
|
122
120
|
end
|
123
121
|
end
|
124
122
|
|
@@ -130,9 +128,7 @@ module Flatware
|
|
130
128
|
private
|
131
129
|
|
132
130
|
def socket
|
133
|
-
@socket ||= Flatware.socket(ZMQ::PUSH
|
134
|
-
socket.connect 'ipc://sink'
|
135
|
-
end
|
131
|
+
@socket ||= Flatware.socket(ZMQ::PUSH, connect: PORT)
|
136
132
|
end
|
137
133
|
end
|
138
134
|
end
|
data/lib/flatware/summary.rb
CHANGED
@@ -14,12 +14,23 @@ module Flatware
|
|
14
14
|
def summarize
|
15
15
|
2.times { io.puts }
|
16
16
|
print_steps :failed
|
17
|
+
print_failed_scenarios scenarios
|
17
18
|
print_counts 'scenario', scenarios
|
18
19
|
print_counts 'step', steps
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
22
23
|
|
24
|
+
def print_failed_scenarios(scenarios)
|
25
|
+
return unless scenarios.any? &with_status(:failed)
|
26
|
+
|
27
|
+
io.puts format_string "Failing Scenarios:", :failed
|
28
|
+
scenarios.select(&with_status(:failed)).sort_by(&:file_colon_line).each do |scenario|
|
29
|
+
io.puts format_string(scenario.file_colon_line, :failed) + format_string(" # Scenario: " + scenario.name, :comment)
|
30
|
+
end
|
31
|
+
io.puts
|
32
|
+
end
|
33
|
+
|
23
34
|
def print_steps(status)
|
24
35
|
print_elements steps.select(&with_status(status)), status, 'steps'
|
25
36
|
end
|
data/lib/flatware/version.rb
CHANGED
data/lib/flatware/worker.rb
CHANGED
@@ -20,8 +20,7 @@ module Flatware
|
|
20
20
|
time = Benchmark.realtime do
|
21
21
|
fireable
|
22
22
|
report_for_duty
|
23
|
-
fireable.until_fired task do |
|
24
|
-
job = Marshal.load work
|
23
|
+
fireable.until_fired task do |job|
|
25
24
|
log 'working!'
|
26
25
|
Cucumber.run job.id, job.args
|
27
26
|
Sink.finished job
|
@@ -43,9 +42,7 @@ module Flatware
|
|
43
42
|
end
|
44
43
|
|
45
44
|
def task
|
46
|
-
@task ||= Flatware.socket
|
47
|
-
task.connect Dispatcher::DISPATCH_PORT
|
48
|
-
end
|
45
|
+
@task ||= Flatware.socket ZMQ::REQ, connect: Dispatcher::PORT
|
49
46
|
end
|
50
47
|
|
51
48
|
def report_for_duty
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flatware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: ffi-rzmq
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
version: 1.0.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: thor
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,49 +64,49 @@ dependencies:
|
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: 0.5.1
|
70
70
|
type: :development
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
75
|
+
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: 0.5.1
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
name: rake
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
85
|
+
version: 10.0.3
|
86
86
|
type: :development
|
87
87
|
prerelease: false
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
89
|
none: false
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
93
|
+
version: 10.0.3
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
95
|
name: rspec
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
|
-
- -
|
99
|
+
- - ~>
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 2.13.0
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
|
-
- -
|
107
|
+
- - ~>
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
109
|
+
version: 2.13.0
|
110
110
|
description: A distributed cucumber runner
|
111
111
|
email: brian@hashrocket.com
|
112
112
|
executables:
|
@@ -124,7 +124,9 @@ files:
|
|
124
124
|
- lib/flatware/cucumber/runtime.rb
|
125
125
|
- lib/flatware/dispatcher.rb
|
126
126
|
- lib/flatware/fireable.rb
|
127
|
+
- lib/flatware/processor_info.rb
|
127
128
|
- lib/flatware/result.rb
|
129
|
+
- lib/flatware/scenario_decorator.rb
|
128
130
|
- lib/flatware/scenario_result.rb
|
129
131
|
- lib/flatware/sink.rb
|
130
132
|
- lib/flatware/step_result.rb
|
@@ -155,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
157
|
version: '0'
|
156
158
|
requirements: []
|
157
159
|
rubyforge_project:
|
158
|
-
rubygems_version: 1.8.
|
160
|
+
rubygems_version: 1.8.25
|
159
161
|
signing_key:
|
160
162
|
specification_version: 3
|
161
163
|
summary: A distributed cucumber runner
|