cucumber-wire 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/.rspec +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +20 -0
- data/README.md +1 -0
- data/Rakefile +13 -0
- data/cucumber-wire.gemspec +28 -0
- data/features/erb_configuration.feature +54 -0
- data/features/handle_unexpected_response.feature +29 -0
- data/features/invoke_message.feature +212 -0
- data/features/readme.md +26 -0
- data/features/snippets_message.feature +47 -0
- data/features/step_definitions/aruba_steps.rb +1 -0
- data/features/step_definitions/wire_steps.rb +58 -0
- data/features/step_matches_message.feature +79 -0
- data/features/support/fake_wire_server.rb +80 -0
- data/features/table_diffing.feature +124 -0
- data/features/tags.feature +86 -0
- data/features/timeouts.feature +63 -0
- data/lib/cucumber/wire.rb +5 -0
- data/lib/cucumber/wire/add_hooks_filter.rb +25 -0
- data/lib/cucumber/wire/configuration.rb +38 -0
- data/lib/cucumber/wire/connection.rb +63 -0
- data/lib/cucumber/wire/connections.rb +50 -0
- data/lib/cucumber/wire/data_packet.rb +34 -0
- data/lib/cucumber/wire/exception.rb +32 -0
- data/lib/cucumber/wire/plugin.rb +32 -0
- data/lib/cucumber/wire/protocol.rb +43 -0
- data/lib/cucumber/wire/protocol/requests.rb +128 -0
- data/lib/cucumber/wire/request_handler.rb +32 -0
- data/lib/cucumber/wire/snippet.rb +35 -0
- data/lib/cucumber/wire/step_definition.rb +21 -0
- data/lib/cucumber/wire/version +1 -0
- data/spec/cucumber/wire/configuration_spec.rb +63 -0
- data/spec/cucumber/wire/connection_spec.rb +64 -0
- data/spec/cucumber/wire/connections_spec.rb +23 -0
- data/spec/cucumber/wire/data_packet_spec.rb +43 -0
- data/spec/cucumber/wire/exception_spec.rb +50 -0
- metadata +157 -0
@@ -0,0 +1 @@
|
|
1
|
+
require "aruba/cucumber"
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Given /^there is a wire server (running |)on port (\d+) which understands the following protocol:$/ do |running, port, table|
|
2
|
+
protocol = table.hashes.map do |table_hash|
|
3
|
+
table_hash['response'] = table_hash['response'].gsub(/\n/, '\n')
|
4
|
+
table_hash
|
5
|
+
end
|
6
|
+
|
7
|
+
@server = FakeWireServer.new(port.to_i, protocol)
|
8
|
+
start_wire_server if running.strip == "running"
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^the wire server takes (.*) seconds to respond to the invoke message$/ do |timeout|
|
12
|
+
@server.delay_response(:invoke, timeout.to_f)
|
13
|
+
start_wire_server
|
14
|
+
end
|
15
|
+
|
16
|
+
Given /^I have environment variable (\w+) set to "([^"]*)"$/ do |variable, value|
|
17
|
+
set_env(variable, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
Then(/^the wire server should have received the following messages:$/) do |expected_messages|
|
21
|
+
expect(messages_received).to eq expected_messages.raw.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
module WireHelper
|
25
|
+
attr_reader :messages_received
|
26
|
+
|
27
|
+
def start_wire_server
|
28
|
+
@messages_received = []
|
29
|
+
reader, writer = IO.pipe
|
30
|
+
@wire_pid = fork {
|
31
|
+
reader.close
|
32
|
+
@server.run(writer)
|
33
|
+
}
|
34
|
+
writer.close
|
35
|
+
Thread.new do
|
36
|
+
while message = reader.gets
|
37
|
+
@messages_received << message.strip
|
38
|
+
end
|
39
|
+
end
|
40
|
+
at_exit { stop_wire_server }
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop_wire_server
|
44
|
+
return unless @wire_pid
|
45
|
+
Process.kill('KILL', @wire_pid)
|
46
|
+
Process.wait(@wire_pid)
|
47
|
+
rescue Errno::ESRCH
|
48
|
+
# No such process - wire server has already been stopped by the After hook
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Before do
|
53
|
+
extend(WireHelper)
|
54
|
+
end
|
55
|
+
|
56
|
+
After do
|
57
|
+
stop_wire_server
|
58
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
Feature: Step matches message
|
2
|
+
|
3
|
+
When the features have been parsed, Cucumber will send a `step_matches`
|
4
|
+
message to ask the wire server if it can match a step name. This happens for
|
5
|
+
each of the steps in each of the features.
|
6
|
+
|
7
|
+
The wire server replies with an array of StepMatch objects.
|
8
|
+
|
9
|
+
When each StepMatch is returned, it contains the following data:
|
10
|
+
|
11
|
+
* `id` - identifier for the step definition to be used later when if it
|
12
|
+
needs to be invoked. The identifier can be any string value and
|
13
|
+
is simply used for the wire server's own reference.
|
14
|
+
* `args` - any argument values as captured by the wire end's own regular
|
15
|
+
expression (or other argument matching) process.
|
16
|
+
|
17
|
+
Background:
|
18
|
+
Given a file named "features/wired.feature" with:
|
19
|
+
"""
|
20
|
+
Feature: High strung
|
21
|
+
Scenario: Wired
|
22
|
+
Given we're all wired
|
23
|
+
|
24
|
+
"""
|
25
|
+
And a file named "features/step_definitions/some_remote_place.wire" with:
|
26
|
+
"""
|
27
|
+
host: localhost
|
28
|
+
port: 54321
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
Scenario: Dry run finds no step match
|
33
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
34
|
+
| request | response |
|
35
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
|
36
|
+
When I run `cucumber --dry-run --no-snippets -f progress`
|
37
|
+
And it should pass with:
|
38
|
+
"""
|
39
|
+
U
|
40
|
+
|
41
|
+
1 scenario (1 undefined)
|
42
|
+
1 step (1 undefined)
|
43
|
+
|
44
|
+
"""
|
45
|
+
|
46
|
+
Scenario: Dry run finds a step match
|
47
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
48
|
+
| request | response |
|
49
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
50
|
+
When I run `cucumber --dry-run -f progress`
|
51
|
+
And it should pass with:
|
52
|
+
"""
|
53
|
+
-
|
54
|
+
|
55
|
+
1 scenario (1 skipped)
|
56
|
+
1 step (1 skipped)
|
57
|
+
|
58
|
+
"""
|
59
|
+
|
60
|
+
Scenario: Step matches returns details about the remote step definition
|
61
|
+
|
62
|
+
Optionally, the StepMatch can also contain a source reference, and a native
|
63
|
+
regexp string which will be used by some formatters.
|
64
|
+
|
65
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
66
|
+
| request | response |
|
67
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[], "source":"MyApp.MyClass:123", "regexp":"we.*"}]] |
|
68
|
+
When I run `cucumber -f stepdefs --dry-run`
|
69
|
+
Then it should pass with:
|
70
|
+
"""
|
71
|
+
-
|
72
|
+
|
73
|
+
we.* # MyApp.MyClass:123
|
74
|
+
|
75
|
+
1 scenario (1 skipped)
|
76
|
+
1 step (1 skipped)
|
77
|
+
|
78
|
+
"""
|
79
|
+
And the stderr should not contain anything
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
class FakeWireServer
|
5
|
+
def initialize(port, protocol_table)
|
6
|
+
@port, @protocol_table = port, protocol_table
|
7
|
+
@delays = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(io)
|
11
|
+
@server = TCPServer.open(@port)
|
12
|
+
loop { handle_connections(io) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def delay_response(message, delay)
|
16
|
+
@delays[message] = delay
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle_connections(io)
|
22
|
+
Thread.start(@server.accept) { |socket| open_session_on socket, io }
|
23
|
+
end
|
24
|
+
|
25
|
+
def open_session_on(socket, io)
|
26
|
+
begin
|
27
|
+
on_message = lambda { |message| io.puts message }
|
28
|
+
SocketSession.new(socket, @protocol_table, @delays, on_message).start
|
29
|
+
rescue Exception => e
|
30
|
+
raise e
|
31
|
+
ensure
|
32
|
+
socket.close
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class SocketSession
|
37
|
+
def initialize(socket, protocol, delays, on_message)
|
38
|
+
@socket = socket
|
39
|
+
@protocol = protocol
|
40
|
+
@delays = delays
|
41
|
+
@on_message = on_message
|
42
|
+
end
|
43
|
+
|
44
|
+
def start
|
45
|
+
while message = @socket.gets
|
46
|
+
handle(message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def handle(data)
|
53
|
+
if protocol_entry = response_to(data.strip)
|
54
|
+
sleep delay(data)
|
55
|
+
@on_message.call(MultiJson.load(protocol_entry['request'])[0])
|
56
|
+
send_response(protocol_entry['response'])
|
57
|
+
else
|
58
|
+
serialized_exception = { :message => "Not understood: #{data}", :backtrace => [] }
|
59
|
+
send_response(['fail', serialized_exception ].to_json)
|
60
|
+
end
|
61
|
+
rescue => e
|
62
|
+
send_response(['fail', { :message => e.message, :backtrace => e.backtrace, :exception => e.class } ].to_json)
|
63
|
+
end
|
64
|
+
|
65
|
+
def response_to(data)
|
66
|
+
@protocol.detect do |entry|
|
67
|
+
MultiJson.load(entry['request']) == MultiJson.load(data)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_response(response)
|
72
|
+
@socket.puts response + "\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
def delay(data)
|
76
|
+
message = MultiJson.load(data.strip)[0]
|
77
|
+
@delays[message.to_sym] || 0
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
Feature: Wire protocol table diffing
|
2
|
+
|
3
|
+
In order to use the amazing functionality in the Cucumber table object
|
4
|
+
As a wire server
|
5
|
+
I want to be able to ask for a table diff during a step definition invocation
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given a file named "features/wired.feature" with:
|
9
|
+
"""
|
10
|
+
Feature: Hello
|
11
|
+
Scenario: Wired
|
12
|
+
Given we're all wired
|
13
|
+
|
14
|
+
"""
|
15
|
+
And a file named "features/step_definitions/some_remote_place.wire" with:
|
16
|
+
"""
|
17
|
+
host: localhost
|
18
|
+
port: 54321
|
19
|
+
|
20
|
+
"""
|
21
|
+
|
22
|
+
@spawn
|
23
|
+
Scenario: Invoke a step definition tries to diff the table and fails
|
24
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
25
|
+
| request | response |
|
26
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
27
|
+
| ["begin_scenario"] | ["success"] |
|
28
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a","b"],["c","d"]],[["x","y"],["z","z"]]]] |
|
29
|
+
| ["diff_failed"] | ["fail",{"message":"Not same", "exception":"DifferentException", "backtrace":["a.cs:12","b.cs:34"]}] |
|
30
|
+
| ["end_scenario"] | ["success"] |
|
31
|
+
When I run `cucumber -f progress --backtrace -q`
|
32
|
+
Then the stderr should not contain anything
|
33
|
+
And it should fail with exactly:
|
34
|
+
"""
|
35
|
+
F
|
36
|
+
|
37
|
+
(::) failed steps (::)
|
38
|
+
|
39
|
+
Not same (DifferentException from localhost:54321)
|
40
|
+
a.cs:12
|
41
|
+
b.cs:34
|
42
|
+
features/wired.feature:3:in `Given we're all wired'
|
43
|
+
|
44
|
+
Failing Scenarios:
|
45
|
+
cucumber features/wired.feature:2
|
46
|
+
|
47
|
+
1 scenario (1 failed)
|
48
|
+
1 step (1 failed)
|
49
|
+
|
50
|
+
"""
|
51
|
+
|
52
|
+
Scenario: Invoke a step definition tries to diff the table and passes
|
53
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
54
|
+
| request | response |
|
55
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
56
|
+
| ["begin_scenario"] | ["success"] |
|
57
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
|
58
|
+
| ["diff_ok"] | ["success"] |
|
59
|
+
| ["end_scenario"] | ["success"] |
|
60
|
+
When I run `cucumber -f progress -q`
|
61
|
+
Then it should pass with exactly:
|
62
|
+
"""
|
63
|
+
.
|
64
|
+
|
65
|
+
1 scenario (1 passed)
|
66
|
+
1 step (1 passed)
|
67
|
+
|
68
|
+
"""
|
69
|
+
|
70
|
+
@spawn
|
71
|
+
Scenario: Invoke a step definition which successfully diffs a table but then fails
|
72
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
73
|
+
| request | response |
|
74
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
75
|
+
| ["begin_scenario"] | ["success"] |
|
76
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
|
77
|
+
| ["diff_ok"] | ["fail",{"message":"I wanted things to be different for us"}] |
|
78
|
+
| ["end_scenario"] | ["success"] |
|
79
|
+
When I run `cucumber -f progress -q`
|
80
|
+
Then it should fail with exactly:
|
81
|
+
"""
|
82
|
+
F
|
83
|
+
|
84
|
+
(::) failed steps (::)
|
85
|
+
|
86
|
+
I wanted things to be different for us (Cucumber::Wire::Exception)
|
87
|
+
features/wired.feature:3:in `Given we're all wired'
|
88
|
+
|
89
|
+
Failing Scenarios:
|
90
|
+
cucumber features/wired.feature:2
|
91
|
+
|
92
|
+
1 scenario (1 failed)
|
93
|
+
1 step (1 failed)
|
94
|
+
|
95
|
+
"""
|
96
|
+
|
97
|
+
@spawn
|
98
|
+
Scenario: Invoke a step definition which asks for an immediate diff that fails
|
99
|
+
Given there is a wire server running on port 54321 which understands the following protocol:
|
100
|
+
| request | response |
|
101
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
102
|
+
| ["begin_scenario"] | ["success"] |
|
103
|
+
| ["invoke",{"id":"1","args":[]}] | ["diff!",[[["a"]],[["b"]]]] |
|
104
|
+
| ["end_scenario"] | ["success"] |
|
105
|
+
When I run `cucumber -f progress -q`
|
106
|
+
And it should fail with exactly:
|
107
|
+
"""
|
108
|
+
F
|
109
|
+
|
110
|
+
(::) failed steps (::)
|
111
|
+
|
112
|
+
Tables were not identical:
|
113
|
+
|
114
|
+
| (-) a | (+) b |
|
115
|
+
(Cucumber::MultilineArgument::DataTable::Different)
|
116
|
+
features/wired.feature:3:in `Given we're all wired'
|
117
|
+
|
118
|
+
Failing Scenarios:
|
119
|
+
cucumber features/wired.feature:2
|
120
|
+
|
121
|
+
1 scenario (1 failed)
|
122
|
+
1 step (1 failed)
|
123
|
+
|
124
|
+
"""
|
@@ -0,0 +1,86 @@
|
|
1
|
+
Feature: Wire protocol tags
|
2
|
+
|
3
|
+
In order to use Before and After hooks in a wire server, we send tags with the
|
4
|
+
scenario in the begin_scenario and end_scenario messages
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given a file named "features/step_definitions/some_remote_place.wire" with:
|
8
|
+
"""
|
9
|
+
host: localhost
|
10
|
+
port: 54321
|
11
|
+
|
12
|
+
"""
|
13
|
+
|
14
|
+
Scenario: Run a scenario
|
15
|
+
Given a file named "features/wired.feature" with:
|
16
|
+
"""
|
17
|
+
@foo @bar
|
18
|
+
Feature: Wired
|
19
|
+
|
20
|
+
@baz
|
21
|
+
Scenario: Everybody's Wired
|
22
|
+
Given we're all wired
|
23
|
+
|
24
|
+
"""
|
25
|
+
And there is a wire server running on port 54321 which understands the following protocol:
|
26
|
+
| request | response |
|
27
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
28
|
+
| ["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
|
29
|
+
| ["invoke",{"id":"1","args":[]}] | ["success"] |
|
30
|
+
| ["end_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
|
31
|
+
When I run `cucumber -f pretty -q`
|
32
|
+
Then the stderr should not contain anything
|
33
|
+
And it should pass with:
|
34
|
+
"""
|
35
|
+
@foo @bar
|
36
|
+
Feature: Wired
|
37
|
+
|
38
|
+
@baz
|
39
|
+
Scenario: Everybody's Wired
|
40
|
+
Given we're all wired
|
41
|
+
|
42
|
+
1 scenario (1 passed)
|
43
|
+
1 step (1 passed)
|
44
|
+
|
45
|
+
"""
|
46
|
+
|
47
|
+
Scenario: Run a scenario outline example
|
48
|
+
Given a file named "features/wired.feature" with:
|
49
|
+
"""
|
50
|
+
@foo @bar
|
51
|
+
Feature: Wired
|
52
|
+
|
53
|
+
@baz
|
54
|
+
Scenario Outline: Everybody's Wired
|
55
|
+
Given we're all <something>
|
56
|
+
|
57
|
+
Examples:
|
58
|
+
| something |
|
59
|
+
| wired |
|
60
|
+
|
61
|
+
"""
|
62
|
+
And there is a wire server running on port 54321 which understands the following protocol:
|
63
|
+
| request | response |
|
64
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
|
65
|
+
| ["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
|
66
|
+
| ["invoke",{"id":"1","args":[]}] | ["success"] |
|
67
|
+
| ["end_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
|
68
|
+
When I run `cucumber -f pretty -q`
|
69
|
+
Then the stderr should not contain anything
|
70
|
+
And it should pass with exactly:
|
71
|
+
"""
|
72
|
+
@foo @bar
|
73
|
+
Feature: Wired
|
74
|
+
|
75
|
+
@baz
|
76
|
+
Scenario Outline: Everybody's Wired
|
77
|
+
Given we're all <something>
|
78
|
+
|
79
|
+
Examples:
|
80
|
+
| something |
|
81
|
+
| wired |
|
82
|
+
|
83
|
+
1 scenario (1 passed)
|
84
|
+
1 step (1 passed)
|
85
|
+
|
86
|
+
"""
|
@@ -0,0 +1,63 @@
|
|
1
|
+
Feature: Wire protocol timeouts
|
2
|
+
|
3
|
+
We don't want Cucumber to hang forever on a wire server that's not even there,
|
4
|
+
but equally we need to give the user the flexibility to allow step definitions
|
5
|
+
to take a while to execute, if that's what they need.
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given a file named "features/wired.feature" with:
|
9
|
+
"""
|
10
|
+
Feature: Telegraphy
|
11
|
+
Scenario: Wired
|
12
|
+
Given we're all wired
|
13
|
+
|
14
|
+
"""
|
15
|
+
|
16
|
+
Scenario: Try to talk to a server that's not there
|
17
|
+
Given a file named "features/step_definitions/some_remote_place.wire" with:
|
18
|
+
"""
|
19
|
+
host: localhost
|
20
|
+
port: 54321
|
21
|
+
|
22
|
+
"""
|
23
|
+
When I run `cucumber -f progress`
|
24
|
+
Then the stderr should contain:
|
25
|
+
"""
|
26
|
+
Unable to contact the wire server at localhost:54321
|
27
|
+
"""
|
28
|
+
|
29
|
+
@spawn
|
30
|
+
Scenario: Invoke a step definition that takes longer than its timeout
|
31
|
+
Given a file named "features/step_definitions/some_remote_place.wire" with:
|
32
|
+
"""
|
33
|
+
host: localhost
|
34
|
+
port: 54321
|
35
|
+
timeout:
|
36
|
+
invoke: 0.1
|
37
|
+
|
38
|
+
"""
|
39
|
+
And there is a wire server on port 54321 which understands the following protocol:
|
40
|
+
| request | response |
|
41
|
+
| ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[{"val":"wired", "pos":10}]}]] |
|
42
|
+
| ["begin_scenario"] | ["success"] |
|
43
|
+
| ["invoke",{"id":"1","args":["wired"]}] | ["success"] |
|
44
|
+
| ["end_scenario"] | ["success"] |
|
45
|
+
And the wire server takes 0.2 seconds to respond to the invoke message
|
46
|
+
When I run `cucumber -f pretty -q`
|
47
|
+
Then the stderr should not contain anything
|
48
|
+
And it should fail with exactly:
|
49
|
+
"""
|
50
|
+
Feature: Telegraphy
|
51
|
+
|
52
|
+
Scenario: Wired
|
53
|
+
Given we're all wired
|
54
|
+
Timed out calling wire server with message 'invoke' (Timeout::Error)
|
55
|
+
features/wired.feature:3:in `Given we're all wired'
|
56
|
+
|
57
|
+
Failing Scenarios:
|
58
|
+
cucumber features/wired.feature:2
|
59
|
+
|
60
|
+
1 scenario (1 failed)
|
61
|
+
1 step (1 failed)
|
62
|
+
|
63
|
+
"""
|