message-driver 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|