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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile +20 -0
  5. data/README.md +1 -0
  6. data/Rakefile +13 -0
  7. data/cucumber-wire.gemspec +28 -0
  8. data/features/erb_configuration.feature +54 -0
  9. data/features/handle_unexpected_response.feature +29 -0
  10. data/features/invoke_message.feature +212 -0
  11. data/features/readme.md +26 -0
  12. data/features/snippets_message.feature +47 -0
  13. data/features/step_definitions/aruba_steps.rb +1 -0
  14. data/features/step_definitions/wire_steps.rb +58 -0
  15. data/features/step_matches_message.feature +79 -0
  16. data/features/support/fake_wire_server.rb +80 -0
  17. data/features/table_diffing.feature +124 -0
  18. data/features/tags.feature +86 -0
  19. data/features/timeouts.feature +63 -0
  20. data/lib/cucumber/wire.rb +5 -0
  21. data/lib/cucumber/wire/add_hooks_filter.rb +25 -0
  22. data/lib/cucumber/wire/configuration.rb +38 -0
  23. data/lib/cucumber/wire/connection.rb +63 -0
  24. data/lib/cucumber/wire/connections.rb +50 -0
  25. data/lib/cucumber/wire/data_packet.rb +34 -0
  26. data/lib/cucumber/wire/exception.rb +32 -0
  27. data/lib/cucumber/wire/plugin.rb +32 -0
  28. data/lib/cucumber/wire/protocol.rb +43 -0
  29. data/lib/cucumber/wire/protocol/requests.rb +128 -0
  30. data/lib/cucumber/wire/request_handler.rb +32 -0
  31. data/lib/cucumber/wire/snippet.rb +35 -0
  32. data/lib/cucumber/wire/step_definition.rb +21 -0
  33. data/lib/cucumber/wire/version +1 -0
  34. data/spec/cucumber/wire/configuration_spec.rb +63 -0
  35. data/spec/cucumber/wire/connection_spec.rb +64 -0
  36. data/spec/cucumber/wire/connections_spec.rb +23 -0
  37. data/spec/cucumber/wire/data_packet_spec.rb +43 -0
  38. data/spec/cucumber/wire/exception_spec.rb +50 -0
  39. 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
+ """