message-driver 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.rubocop.yml +26 -2
- data/.rubocop_todo.yml +15 -123
- data/.travis.yml +2 -1
- data/CHANGELOG.md +10 -1
- data/Gemfile +15 -6
- data/Rakefile +23 -12
- data/ci/reset_vhost +8 -3
- data/ci/travis_setup +0 -3
- data/features/.nav +6 -1
- data/features/CHANGELOG.md +10 -1
- data/features/amqp_specific_features/binding_amqp_destinations.feature +1 -0
- data/features/amqp_specific_features/declaring_amqp_exchanges.feature +1 -0
- data/features/amqp_specific_features/server_named_destinations.feature +1 -0
- data/features/destination_metadata.feature +26 -0
- data/features/logging.feature +1 -1
- data/features/middleware/middleware_basics.feature +91 -0
- data/features/middleware/middleware_ordering.feature +60 -0
- data/features/middleware/middleware_parameters.feature +43 -0
- data/features/middleware/middleware_with_blocks.feature +85 -0
- data/features/step_definitions/dynamic_destinations_steps.rb +1 -1
- data/features/step_definitions/message_consumers_steps.rb +5 -0
- data/features/step_definitions/middleware_steps.rb +10 -0
- data/features/step_definitions/steps.rb +10 -2
- data/features/support/env.rb +4 -3
- data/features/support/firewall_helper.rb +1 -1
- data/features/support/message_table_matcher.rb +3 -2
- data/features/support/no_error_matcher.rb +2 -2
- data/features/support/test_runner.rb +11 -57
- data/features/support/transforms.rb +12 -10
- data/lib/message_driver.rb +3 -1
- data/lib/message_driver/adapters/base.rb +11 -11
- data/lib/message_driver/adapters/bunny_adapter.rb +189 -132
- data/lib/message_driver/adapters/in_memory_adapter.rb +51 -34
- data/lib/message_driver/adapters/stomp_adapter.rb +22 -23
- data/lib/message_driver/broker.rb +21 -16
- data/lib/message_driver/client.rb +15 -16
- data/lib/message_driver/destination.rb +26 -8
- data/lib/message_driver/message.rb +5 -4
- data/lib/message_driver/middleware.rb +8 -0
- data/lib/message_driver/middleware/base.rb +19 -0
- data/lib/message_driver/middleware/block_middleware.rb +33 -0
- data/lib/message_driver/middleware/middleware_stack.rb +61 -0
- data/lib/message_driver/subscription.rb +2 -2
- data/lib/message_driver/version.rb +1 -1
- data/message-driver.gemspec +3 -4
- data/spec/integration/bunny/amqp_integration_spec.rb +21 -82
- data/spec/integration/bunny/bunny_adapter_spec.rb +288 -268
- data/spec/integration/in_memory/in_memory_adapter_spec.rb +93 -90
- data/spec/integration/stomp/stomp_adapter_spec.rb +126 -93
- data/spec/spec_helper.rb +11 -9
- data/spec/support/shared/adapter_examples.rb +1 -1
- data/spec/support/shared/client_ack_examples.rb +4 -4
- data/spec/support/shared/context_examples.rb +6 -4
- data/spec/support/shared/destination_examples.rb +54 -14
- data/spec/support/shared/subscription_examples.rb +33 -26
- data/spec/support/shared/transaction_examples.rb +12 -12
- data/spec/support/utils.rb +1 -1
- data/spec/units/message_driver/adapters/base_spec.rb +42 -40
- data/spec/units/message_driver/broker_spec.rb +38 -38
- data/spec/units/message_driver/client_spec.rb +87 -87
- data/spec/units/message_driver/destination_spec.rb +16 -11
- data/spec/units/message_driver/message_spec.rb +96 -70
- data/spec/units/message_driver/middleware/base_spec.rb +30 -0
- data/spec/units/message_driver/middleware/block_middleware_spec.rb +82 -0
- data/spec/units/message_driver/middleware/middleware_stack_spec.rb +165 -0
- data/spec/units/message_driver/subscription_spec.rb +18 -16
- data/test_lib/broker_config.rb +21 -5
- data/test_lib/coverage.rb +11 -0
- data/test_lib/provider/base.rb +59 -0
- data/test_lib/provider/in_memory.rb +6 -0
- data/test_lib/provider/rabbitmq.rb +67 -0
- metadata +46 -35
@@ -29,3 +29,29 @@ Feature: Destination Metadata
|
|
29
29
|
|
30
30
|
Then I expect to have no errors
|
31
31
|
And I expect to find 2 messages on :my_queue
|
32
|
+
|
33
|
+
Scenario: Check the consumer count when the queue has no consumers
|
34
|
+
When I execute the following code
|
35
|
+
"""ruby
|
36
|
+
destination = MessageDriver::Client.find_destination(:my_queue)
|
37
|
+
expect(destination.consumer_count).to eq(0)
|
38
|
+
"""
|
39
|
+
|
40
|
+
Then I expect to have no errors
|
41
|
+
|
42
|
+
Scenario: Check the consumer count when the queue has consumers
|
43
|
+
Given I create some subscriptions
|
44
|
+
"""ruby
|
45
|
+
3.times do
|
46
|
+
MessageDriver::Client.subscribe_with(:my_queue) do |message|
|
47
|
+
puts message.inspect
|
48
|
+
end
|
49
|
+
end
|
50
|
+
"""
|
51
|
+
When I execute the following code
|
52
|
+
"""ruby
|
53
|
+
destination = MessageDriver::Client.find_destination(:my_queue)
|
54
|
+
expect(destination.consumer_count).to eq(3)
|
55
|
+
"""
|
56
|
+
|
57
|
+
Then I expect to have no errors
|
data/features/logging.feature
CHANGED
@@ -0,0 +1,91 @@
|
|
1
|
+
@bunny
|
2
|
+
@in_memory
|
3
|
+
Feature: Middleware Basics
|
4
|
+
|
5
|
+
Middlewares can be used to transform messages that are about to be published
|
6
|
+
or that are about to be consumed. This allows for handling of things like
|
7
|
+
serializing and deserializing the message body in a way that is transparent to
|
8
|
+
your application code.
|
9
|
+
|
10
|
+
Middlewares are applied in a stack to destinations, much like Rack middleware.
|
11
|
+
As a message that is about to be consumed, it starts by coming in the top of
|
12
|
+
the middleware stack and works it's way down before it is returned by
|
13
|
+
`pop_message` or passed to a consumer.
|
14
|
+
|
15
|
+
For messages that are being published, they start at the bottom of the stack
|
16
|
+
and work their way up until they are finally passed to the underlying driver
|
17
|
+
and sent to the message broker.
|
18
|
+
|
19
|
+
Background:
|
20
|
+
Given I am connected to the broker
|
21
|
+
And I have a destination :middleware_queue with no messages on it
|
22
|
+
And I have a middleware class
|
23
|
+
"""ruby
|
24
|
+
class ExampleMiddleware < MessageDriver::Middleware::Base
|
25
|
+
def on_publish(body, headers, properties)
|
26
|
+
[body+':about_to_publish', headers, properties]
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_consume(body, headers, properties)
|
30
|
+
['about_to_be_consumed:'+body, headers, properties]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
"""
|
34
|
+
|
35
|
+
Scenario: The middleware stack of a destination is initially empty
|
36
|
+
When I execute the following code
|
37
|
+
"""ruby
|
38
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
39
|
+
expect(destination.middleware).to be_empty
|
40
|
+
"""
|
41
|
+
Then I expect to have no errors
|
42
|
+
|
43
|
+
|
44
|
+
Scenario: Adding a piece of middleware to a destination
|
45
|
+
When I execute the following code
|
46
|
+
"""ruby
|
47
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
48
|
+
destination.middleware.append ExampleMiddleware
|
49
|
+
"""
|
50
|
+
|
51
|
+
Then I expect the following check to pass
|
52
|
+
"""ruby
|
53
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
54
|
+
expect(destination.middleware).to include(an_instance_of(ExampleMiddleware))
|
55
|
+
"""
|
56
|
+
|
57
|
+
|
58
|
+
Scenario: Middleware is applied to messages as they are published
|
59
|
+
When I append middleware "ExampleMiddleware" to :middleware_queue
|
60
|
+
And I send the following messages to :middleware_queue
|
61
|
+
| body |
|
62
|
+
| Test Message 1 |
|
63
|
+
| Test Message 2 |
|
64
|
+
|
65
|
+
Then I expect to find the following 2 messages on :middleware_queue
|
66
|
+
| raw_body |
|
67
|
+
| Test Message 1:about_to_publish |
|
68
|
+
| Test Message 2:about_to_publish |
|
69
|
+
|
70
|
+
|
71
|
+
Scenario: Middleware is applied to messages as they are consumed
|
72
|
+
Given I have a destination :dest_queue with no messages on it
|
73
|
+
|
74
|
+
When I send the following messages to :middleware_queue
|
75
|
+
| body |
|
76
|
+
| Test Message 1 |
|
77
|
+
| Test Message 2 |
|
78
|
+
And I append middleware "ExampleMiddleware" to :middleware_queue
|
79
|
+
And I create a subscription
|
80
|
+
"""ruby
|
81
|
+
MessageDriver::Client.subscribe_with(:middleware_queue) do |message|
|
82
|
+
MessageDriver::Client.publish(:dest_queue, message.body)
|
83
|
+
end
|
84
|
+
"""
|
85
|
+
And I let the subscription process
|
86
|
+
|
87
|
+
Then I expect to find no messages on :middleware_queue
|
88
|
+
And I expect to find the following 2 messages on :dest_queue
|
89
|
+
| raw_body |
|
90
|
+
| about_to_be_consumed:Test Message 1 |
|
91
|
+
| about_to_be_consumed:Test Message 2 |
|
@@ -0,0 +1,60 @@
|
|
1
|
+
@bunny
|
2
|
+
@in_memory
|
3
|
+
Feature: Middleware Ordering
|
4
|
+
|
5
|
+
Middleware are applied based on the order they appear in the stack. For
|
6
|
+
publish operations, middlewares are applied bottom of the stack to the top.
|
7
|
+
For consume operations, middleware are applied from the top of the stack to
|
8
|
+
the bottom.
|
9
|
+
|
10
|
+
Scenario: Apply two middlewares to a destination
|
11
|
+
Given I am connected to the broker
|
12
|
+
And I have a destination :middleware_queue with no messages on it
|
13
|
+
And I have a middleware class
|
14
|
+
"""ruby
|
15
|
+
class MiddlewareOne < MessageDriver::Middleware::Base
|
16
|
+
def on_publish(body, headers, properties)
|
17
|
+
[body+':publish1', headers, properties]
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_consume(body, headers, properties)
|
21
|
+
['consume1:'+body, headers, properties]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
"""
|
25
|
+
And I have a middleware class
|
26
|
+
"""ruby
|
27
|
+
class MiddlewareTwo < MessageDriver::Middleware::Base
|
28
|
+
def on_publish(body, headers, properties)
|
29
|
+
[body+':publish2', headers, properties]
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_consume(body, headers, properties)
|
33
|
+
['consume2:'+body, headers, properties]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
"""
|
37
|
+
And I append middleware "MiddlewareOne" to :middleware_queue
|
38
|
+
And I append middleware "MiddlewareTwo" to :middleware_queue
|
39
|
+
|
40
|
+
And I have a destination :dest_queue with no messages on it
|
41
|
+
And I create a subscription
|
42
|
+
"""ruby
|
43
|
+
MessageDriver::Client.subscribe_with(:middleware_queue) do |message|
|
44
|
+
MessageDriver::Client.publish(:dest_queue, message.body)
|
45
|
+
end
|
46
|
+
"""
|
47
|
+
|
48
|
+
When I send the following messages to :middleware_queue
|
49
|
+
| body |
|
50
|
+
| Test Message 1 |
|
51
|
+
| Test Message 2 |
|
52
|
+
| Test Message 3 |
|
53
|
+
And I let the subscription process
|
54
|
+
|
55
|
+
Then I expect to find no messages on :middleware_queue
|
56
|
+
And I expect to find the following 3 messages on :dest_queue
|
57
|
+
| body |
|
58
|
+
| consume1:consume2:Test Message 1:publish1:publish2 |
|
59
|
+
| consume1:consume2:Test Message 2:publish1:publish2 |
|
60
|
+
| consume1:consume2:Test Message 3:publish1:publish2 |
|
@@ -0,0 +1,43 @@
|
|
1
|
+
@bunny
|
2
|
+
@in_memory
|
3
|
+
Feature: Middleware Parameters
|
4
|
+
|
5
|
+
You can provide parameters to your middleware by passing them as additional
|
6
|
+
paremeters to the append and prepend calls.
|
7
|
+
|
8
|
+
Background:
|
9
|
+
Given I am connected to the broker
|
10
|
+
And I have a destination :middleware_queue with no messages on it
|
11
|
+
And I have a middleware class
|
12
|
+
"""ruby
|
13
|
+
class ParameterizedMiddleware < MessageDriver::Middleware::Base
|
14
|
+
|
15
|
+
attr_reader :prefix, :seperator
|
16
|
+
|
17
|
+
def initialize(destination, prefix, seperator)
|
18
|
+
super(destination)
|
19
|
+
@prefix = prefix
|
20
|
+
@seperator = seperator
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_publish(body, headers, properties)
|
24
|
+
["#{prefix}#{seperator}#{body}", headers, properties]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
"""
|
28
|
+
|
29
|
+
Scenario: Adding a parameterized middleware to the stack
|
30
|
+
When I execute the following code
|
31
|
+
"""ruby
|
32
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
33
|
+
destination.middleware.append ParameterizedMiddleware, 'pub_pre', ':'
|
34
|
+
"""
|
35
|
+
And I send the following messages to :middleware_queue
|
36
|
+
| body |
|
37
|
+
| Test Message 1 |
|
38
|
+
| Test Message 2 |
|
39
|
+
|
40
|
+
Then I expect to find the following 2 messages on :middleware_queue
|
41
|
+
| raw_body |
|
42
|
+
| pub_pre:Test Message 1 |
|
43
|
+
| pub_pre:Test Message 2 |
|
@@ -0,0 +1,85 @@
|
|
1
|
+
@bunny
|
2
|
+
@in_memory
|
3
|
+
Feature: Middleware with Blocks
|
4
|
+
|
5
|
+
You can also create middleware by passing a hash with blocks as the input to
|
6
|
+
append or prepend
|
7
|
+
|
8
|
+
Background:
|
9
|
+
Given I am connected to the broker
|
10
|
+
And I have a destination :middleware_queue with no messages on it
|
11
|
+
|
12
|
+
Scenario: providing an on_publish block
|
13
|
+
When I execute the following code
|
14
|
+
"""ruby
|
15
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
16
|
+
destination.middleware.append on_publish: ->(body, headers, properties) { [body+' published with a block!', headers, properties] }
|
17
|
+
"""
|
18
|
+
|
19
|
+
And I send the following messages to :middleware_queue
|
20
|
+
| body |
|
21
|
+
| Test Message 1 |
|
22
|
+
| Test Message 2 |
|
23
|
+
|
24
|
+
Then I expect to find the following 2 messages on :middleware_queue
|
25
|
+
| raw_body |
|
26
|
+
| Test Message 1 published with a block! |
|
27
|
+
| Test Message 2 published with a block! |
|
28
|
+
|
29
|
+
|
30
|
+
Scenario: providing an on_consume block
|
31
|
+
Given I have a destination :dest_queue with no messages on it
|
32
|
+
|
33
|
+
When I execute the following code
|
34
|
+
"""ruby
|
35
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
36
|
+
destination.middleware.append on_consume: ->(body, headers, properties) { [body+' consumed with a block!', headers, properties] }
|
37
|
+
"""
|
38
|
+
|
39
|
+
And I send the following messages to :middleware_queue
|
40
|
+
| body |
|
41
|
+
| Test Message 1 |
|
42
|
+
| Test Message 2 |
|
43
|
+
|
44
|
+
And I create a subscription
|
45
|
+
"""ruby
|
46
|
+
MessageDriver::Client.subscribe_with(:middleware_queue) do |message|
|
47
|
+
MessageDriver::Client.publish(:dest_queue, message.body)
|
48
|
+
end
|
49
|
+
"""
|
50
|
+
And I let the subscription process
|
51
|
+
|
52
|
+
Then I expect to find no messages on :middleware_queue
|
53
|
+
And I expect to find the following 2 messages on :dest_queue
|
54
|
+
| raw_body |
|
55
|
+
| Test Message 1 consumed with a block! |
|
56
|
+
| Test Message 2 consumed with a block! |
|
57
|
+
|
58
|
+
Scenario: providing an on_consume block and an on_publish block
|
59
|
+
Given I have a destination :dest_queue with no messages on it
|
60
|
+
|
61
|
+
When I execute the following code
|
62
|
+
"""ruby
|
63
|
+
destination = MessageDriver::Client.find_destination(:middleware_queue)
|
64
|
+
destination.middleware.append(on_consume: ->(body, headers, properties) { [body + ' consumed', headers, properties] },
|
65
|
+
on_publish: ->(body, headers, properties) { ['published ' + body, headers, properties] })
|
66
|
+
"""
|
67
|
+
|
68
|
+
And I send the following messages to :middleware_queue
|
69
|
+
| body |
|
70
|
+
| Test Message 1 |
|
71
|
+
| Test Message 2 |
|
72
|
+
|
73
|
+
And I create a subscription
|
74
|
+
"""ruby
|
75
|
+
MessageDriver::Client.subscribe_with(:middleware_queue) do |message|
|
76
|
+
MessageDriver::Client.publish(:dest_queue, message.body)
|
77
|
+
end
|
78
|
+
"""
|
79
|
+
And I let the subscription process
|
80
|
+
|
81
|
+
Then I expect to find no messages on :middleware_queue
|
82
|
+
And I expect to find the following 2 messages on :dest_queue
|
83
|
+
| raw_body |
|
84
|
+
| published Test Message 1 consumed |
|
85
|
+
| published Test Message 2 consumed |
|
@@ -7,6 +7,6 @@ Then(/^I expect to find (#{NUMBER}) messages? on the dynamic destination "(#{STR
|
|
7
7
|
expect(test_runner).to have_no_errors
|
8
8
|
dest = MessageDriver::Client[test_runner.broker_name].dynamic_destination(destination, passive: true)
|
9
9
|
messages = test_runner.fetch_messages(dest)
|
10
|
-
expect(messages).to
|
10
|
+
expect(messages.size).to eq(count)
|
11
11
|
expect(messages).to match_message_table(table)
|
12
12
|
end
|
@@ -12,6 +12,11 @@ Given 'I create a subscription' do |src|
|
|
12
12
|
expect(test_runner).to have_no_errors
|
13
13
|
end
|
14
14
|
|
15
|
+
Given 'I create some subscriptions' do |src|
|
16
|
+
test_runner.run_test_code(src)
|
17
|
+
expect(test_runner).to have_no_errors
|
18
|
+
end
|
19
|
+
|
15
20
|
When 'I cancel the subscription' do
|
16
21
|
test_runner.run_test_code('@subscription.unsubscribe')
|
17
22
|
step 'I allow for processing'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Given('I have a middleware class') do |src|
|
2
|
+
write_file('feature_middleware.rb', src)
|
3
|
+
in_current_dir { load './feature_middleware.rb' }
|
4
|
+
end
|
5
|
+
|
6
|
+
When(/^I append middleware "(.*?)" to (#{STRING_OR_SYM})$/) do |class_name, dest_name|
|
7
|
+
klass = Object.const_get(class_name)
|
8
|
+
destination = test_runner.fetch_destination(dest_name)
|
9
|
+
destination.middleware.append klass
|
10
|
+
end
|
@@ -59,14 +59,14 @@ end
|
|
59
59
|
Then(/^I expect to find (#{NUMBER}) messages? on (#{STRING_OR_SYM})$/) do |count, destination|
|
60
60
|
expect(test_runner).to have_no_errors
|
61
61
|
messages = test_runner.fetch_messages(destination)
|
62
|
-
expect(messages).to
|
62
|
+
expect(messages.size).to eq(count), "expected #{count} messages, but got these instead: #{messages.map(&:body)}"
|
63
63
|
end
|
64
64
|
|
65
65
|
Then(/^I expect to find the following (#{NUMBER}) messages? on (#{STRING_OR_SYM})$/) do |count, destination, table|
|
66
66
|
expect(test_runner).to have_no_errors
|
67
67
|
messages = test_runner.fetch_messages(destination)
|
68
68
|
expect(messages).to match_message_table(table)
|
69
|
-
expect(messages).to
|
69
|
+
expect(messages.size).to eq(count)
|
70
70
|
end
|
71
71
|
|
72
72
|
Then(/^I expect to find the following message on (#{STRING_OR_SYM})$/) do |destination, table|
|
@@ -99,3 +99,11 @@ end
|
|
99
99
|
Before do |current_scenario|
|
100
100
|
test_runner.current_feature_file = current_scenario.feature.file
|
101
101
|
end
|
102
|
+
|
103
|
+
Before '@read_queues_directly' do
|
104
|
+
test_runner.provider.read_queues_directly = true
|
105
|
+
end
|
106
|
+
|
107
|
+
After '@read_queues_directly' do
|
108
|
+
test_runner.provider.read_queues_directly = false
|
109
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
ENV['COMMAND_NAME'] = 'features'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'test_lib', 'coverage')
|
4
3
|
require File.join(File.dirname(__FILE__), '..', '..', 'test_lib', 'broker_config')
|
5
4
|
|
6
5
|
require 'aruba/cucumber'
|
7
6
|
require 'message_driver'
|
8
7
|
|
8
|
+
BrokerConfig.setup_provider
|
9
|
+
|
9
10
|
After do
|
10
11
|
MessageDriver::Broker.reset
|
11
12
|
end
|
@@ -13,10 +13,11 @@ RSpec::Matchers.define :match_message_table do |expected_tbl|
|
|
13
13
|
|
14
14
|
match do |messages|
|
15
15
|
@actual = messages_to_hash(messages)
|
16
|
-
@actual
|
16
|
+
expect(@actual).to match_array(expected_hash)
|
17
|
+
true
|
17
18
|
end
|
18
19
|
|
19
|
-
|
20
|
+
failure_message do |_|
|
20
21
|
"expected #{expected_hash} and got #{@actual}"
|
21
22
|
end
|
22
23
|
|