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
@@ -2,126 +2,129 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'message_driver/adapters/in_memory_adapter'
|
4
4
|
|
5
|
-
module MessageDriver
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
module MessageDriver
|
6
|
+
module Adapters
|
7
|
+
RSpec.describe InMemoryAdapter, :in_memory, type: :integration do
|
8
|
+
let(:broker) { double(Broker) }
|
9
|
+
subject(:adapter) { described_class.new(broker) }
|
10
|
+
|
11
|
+
describe '#new_context' do
|
12
|
+
it 'returns a InMemoryAdapter::InMemoryContext' do
|
13
|
+
expect(subject.new_context).to be_a InMemoryAdapter::InMemoryContext
|
14
|
+
end
|
13
15
|
end
|
14
|
-
end
|
15
|
-
|
16
|
-
it_behaves_like 'an adapter'
|
17
|
-
|
18
|
-
describe InMemoryAdapter::InMemoryContext do
|
19
|
-
subject(:adapter_context) { adapter.new_context }
|
20
|
-
|
21
|
-
it_behaves_like 'an adapter context'
|
22
|
-
it_behaves_like 'transactions are not supported'
|
23
|
-
it_behaves_like 'client acks are not supported'
|
24
|
-
it_behaves_like 'subscriptions are supported', InMemoryAdapter::Subscription
|
25
|
-
end
|
26
16
|
|
27
|
-
|
28
|
-
describe 'the resulting destination' do
|
29
|
-
subject(:destination) { adapter.create_destination('my_test_dest') }
|
17
|
+
it_behaves_like 'an adapter'
|
30
18
|
|
31
|
-
|
19
|
+
describe 'InMemoryAdapter::InMemoryContext' do
|
20
|
+
subject(:adapter_context) { adapter.new_context }
|
32
21
|
|
33
|
-
it_behaves_like '
|
34
|
-
|
22
|
+
it_behaves_like 'an adapter context'
|
23
|
+
it_behaves_like 'transactions are not supported'
|
24
|
+
it_behaves_like 'client acks are not supported'
|
25
|
+
it_behaves_like 'subscriptions are supported', InMemoryAdapter::Subscription
|
35
26
|
end
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
dest1 = adapter.create_destination(queue_name)
|
41
|
-
dest2 = adapter.create_destination(queue_name)
|
42
|
-
expect(dest1).to_not be(dest2)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
28
|
+
describe '#create_destination' do
|
29
|
+
describe 'the resulting destination' do
|
30
|
+
subject(:destination) { adapter.create_destination('my_test_dest') }
|
46
31
|
|
47
|
-
|
48
|
-
it 'empties all the destination queues' do
|
49
|
-
destinations = (1..3).map(&adapter.method(:create_destination))
|
50
|
-
destinations.each do |destination|
|
51
|
-
destination.publish("There's always money in the banana stand!", {}, {})
|
52
|
-
end
|
32
|
+
it { is_expected.to be_a InMemoryAdapter::Destination }
|
53
33
|
|
54
|
-
|
34
|
+
it_behaves_like 'a destination'
|
35
|
+
include_examples 'supports #message_count'
|
36
|
+
include_examples 'supports #consumer_count'
|
37
|
+
end
|
55
38
|
|
56
|
-
destinations
|
57
|
-
|
39
|
+
context 'when creating two destinations for the same queue' do
|
40
|
+
it 'creates seperate destination instances' do
|
41
|
+
queue_name = 'my_queue'
|
42
|
+
dest1 = adapter.create_destination(queue_name)
|
43
|
+
dest2 = adapter.create_destination(queue_name)
|
44
|
+
expect(dest1).to_not be(dest2)
|
45
|
+
end
|
58
46
|
end
|
59
47
|
end
|
60
48
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
49
|
+
describe '#reset_after_tests' do
|
50
|
+
it 'empties all the destination queues' do
|
51
|
+
destinations = (1..3).map(&adapter.method(:create_destination))
|
52
|
+
destinations.each do |destination|
|
53
|
+
destination.publish("There's always money in the banana stand!", {}, {})
|
54
|
+
end
|
67
55
|
|
68
|
-
|
56
|
+
adapter.reset_after_tests
|
69
57
|
|
70
|
-
|
71
|
-
|
58
|
+
destinations.each do |destination|
|
59
|
+
expect(destination.message_count).to eq(0)
|
60
|
+
end
|
72
61
|
end
|
73
62
|
|
74
|
-
|
75
|
-
|
63
|
+
it 'removes any existing subscriptions' do
|
64
|
+
destinations = (1..3).map(&adapter.method(:create_destination))
|
65
|
+
consumer = ->(_) {}
|
66
|
+
destinations.each do |destination|
|
67
|
+
destination.subscribe(&consumer)
|
68
|
+
end
|
76
69
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
70
|
+
adapter.reset_after_tests
|
71
|
+
|
72
|
+
destinations.each do |destination|
|
73
|
+
expect(destination.subscription).to be_nil
|
74
|
+
end
|
81
75
|
|
82
|
-
context 'when I have a consumer on one destination' do
|
83
|
-
let(:consumer) { lambda do |_| end }
|
84
|
-
before do
|
85
|
-
dest1.subscribe(&consumer)
|
86
|
-
end
|
87
|
-
it 'is the same consumer on the other destination' do
|
88
|
-
expect(dest2.subscription.consumer).to be(consumer)
|
89
76
|
end
|
90
77
|
end
|
91
78
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
79
|
+
describe 'accessing the same queue from two destinations' do
|
80
|
+
let(:queue_name) { 'my_queue' }
|
81
|
+
let(:dest1) { adapter.create_destination(queue_name) }
|
82
|
+
let(:dest2) { adapter.create_destination(queue_name) }
|
83
|
+
|
84
|
+
context 'when I have a consumer on one destination' do
|
85
|
+
let(:consumer) { ->(_) {} }
|
86
|
+
before do
|
87
|
+
dest1.subscribe(&consumer)
|
88
|
+
end
|
89
|
+
it 'is the same consumer on the other destination' do
|
90
|
+
expect(dest2.subscription.consumer).to be(consumer)
|
91
|
+
end
|
97
92
|
end
|
98
93
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
94
|
+
context 'when I publish a message to one destination' do
|
95
|
+
it 'changes the message_count on the other' do
|
96
|
+
expect do
|
97
|
+
dest1.publish('my test message')
|
98
|
+
end.to change { dest2.message_count }.from(0).to(1)
|
99
|
+
end
|
106
100
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
101
|
+
it 'can be popped off the other' do
|
102
|
+
dest1.publish('my test message')
|
103
|
+
msg = dest2.pop_message
|
104
|
+
expect(msg).to_not be_nil
|
105
|
+
expect(msg.body).to eq('my test message')
|
106
|
+
end
|
111
107
|
end
|
112
108
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
109
|
+
context 'when I pop a message off one destination' do
|
110
|
+
let(:message_body) { 'test popping a message' }
|
111
|
+
before do
|
112
|
+
dest2.publish(message_body)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'changes the message_count on the other' do
|
116
|
+
expect do
|
117
|
+
dest1.pop_message
|
118
|
+
end.to change { dest2.message_count }.from(1).to(0)
|
119
|
+
end
|
117
120
|
end
|
118
121
|
end
|
119
|
-
end
|
120
122
|
|
121
|
-
|
122
|
-
|
123
|
+
describe 'subscribing a consumer' do
|
124
|
+
let(:destination) { adapter.create_destination(:my_queue) }
|
123
125
|
|
124
|
-
|
126
|
+
let(:subscription_type) { MessageDriver::Adapters::InMemoryAdapter::Subscription }
|
127
|
+
end
|
125
128
|
end
|
126
129
|
end
|
127
130
|
end
|
@@ -2,134 +2,167 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
require 'message_driver/adapters/stomp_adapter'
|
4
4
|
|
5
|
-
module MessageDriver
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
module MessageDriver
|
6
|
+
module Adapters
|
7
|
+
RSpec.describe StompAdapter, :stomp, type: :integration do
|
8
|
+
|
9
|
+
let(:valid_connection_attrs) { BrokerConfig.config }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
let(:connection_attrs) { valid_connection_attrs }
|
13
|
+
let(:broker) { double('broker') }
|
14
|
+
|
15
|
+
context 'differing stomp versions' do
|
16
|
+
shared_examples 'raises a stomp error' do
|
17
|
+
it 'raises an error' do
|
18
|
+
stub_const('Stomp::Version::STRING', version)
|
19
|
+
expect do
|
20
|
+
described_class.new(broker, connection_attrs)
|
21
|
+
end.to raise_error MessageDriver::Error, 'stomp 1.3.1 or a later version of the 1.3.x series is required for the stomp adapter'
|
22
|
+
end
|
21
23
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
shared_examples "doesn't raise a stomp error" do
|
25
|
+
it "doesn't raise an an error" do
|
26
|
+
stub_const('Stomp::Version::STRING', version)
|
27
|
+
adapter = nil
|
28
|
+
expect do
|
29
|
+
adapter = described_class.new(broker, connection_attrs)
|
30
|
+
end.to_not raise_error
|
31
|
+
end
|
30
32
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
%w(1.1.0 1.2.9 1.3.0 1.4.0).each do |v|
|
34
|
+
context "stomp version #{v}" do
|
35
|
+
let(:version) { v }
|
36
|
+
include_examples 'raises a stomp error'
|
37
|
+
end
|
36
38
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
%w(1.3.1 1.3.5).each do |v|
|
40
|
+
context "stomp version #{v}" do
|
41
|
+
let(:version) { v }
|
42
|
+
include_examples "doesn't raise a stomp error"
|
43
|
+
end
|
42
44
|
end
|
43
45
|
end
|
44
|
-
end
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
describe 'the resulting config' do
|
48
|
+
let(:connection_attrs) { { hosts: [{ host: 'my_host' }] } }
|
49
|
+
subject(:config) { described_class.new(broker, connection_attrs).config }
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
it 'has the expected values' do
|
52
|
+
is_expected.to eq(
|
53
|
+
connect_headers: { :"accept-version" => '1.1,1.2' },
|
54
|
+
hosts: connection_attrs[:hosts]
|
55
|
+
)
|
56
|
+
end
|
52
57
|
|
53
|
-
|
54
|
-
|
58
|
+
context 'when vhost is specified' do
|
59
|
+
let(:connection_attrs) { { hosts: [{ host: 'my_host' }], vhost: 'my_vhost' } }
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
it 'has the vhost value in the connect headers' do
|
62
|
+
is_expected.not_to have_key(:vhost)
|
63
|
+
is_expected.to include(connect_headers: { :'accept-version' => '1.1,1.2', host: 'my_vhost' })
|
64
|
+
end
|
65
|
+
end
|
59
66
|
|
60
|
-
|
61
|
-
|
67
|
+
context 'when there are things in the connect_headers' do
|
68
|
+
let(:connection_attrs) { { hosts: [{ host: 'my_host' }], connect_headers: { 'foo' => 'bar' } } }
|
62
69
|
|
63
|
-
|
70
|
+
it 'passes them through' do
|
71
|
+
is_expected.to include(connect_headers: { :'accept-version' => '1.1,1.2', 'foo' => 'bar' })
|
72
|
+
end
|
64
73
|
|
65
|
-
|
66
|
-
|
74
|
+
context 'and accept-version is one of the parameters' do
|
75
|
+
let(:connection_attrs) { { hosts: [{ host: 'my_host' }], connect_headers: { 'foo' => 'bar', :"accept-version" => 'foo!' } } }
|
67
76
|
|
68
|
-
|
77
|
+
it 'overrides it' do
|
78
|
+
is_expected.to include(connect_headers: { :'accept-version' => '1.1,1.2', 'foo' => 'bar' })
|
79
|
+
end
|
80
|
+
end
|
69
81
|
end
|
70
82
|
end
|
71
83
|
end
|
72
|
-
end
|
73
84
|
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
shared_context 'a connected stomp adapter' do
|
86
|
+
let(:broker) { MessageDriver::Broker.configure(valid_connection_attrs) }
|
87
|
+
subject(:adapter) { broker.adapter }
|
77
88
|
|
78
|
-
|
79
|
-
|
89
|
+
after do
|
90
|
+
adapter.stop
|
91
|
+
end
|
80
92
|
end
|
81
|
-
end
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
94
|
+
it_behaves_like 'an adapter' do
|
95
|
+
include_context 'a connected stomp adapter'
|
96
|
+
end
|
86
97
|
|
87
|
-
|
88
|
-
|
98
|
+
describe '#new_context' do
|
99
|
+
include_context 'a connected stomp adapter'
|
89
100
|
|
90
|
-
|
91
|
-
|
101
|
+
it 'returns a StompAdapter::StompContext' do
|
102
|
+
expect(adapter.new_context).to be_a StompAdapter::StompContext
|
103
|
+
end
|
92
104
|
end
|
93
|
-
end
|
94
105
|
|
95
|
-
|
96
|
-
|
97
|
-
|
106
|
+
describe StompAdapter::StompContext do
|
107
|
+
include_context 'a connected stomp adapter'
|
108
|
+
subject(:adapter_context) { adapter.new_context }
|
109
|
+
|
110
|
+
it_behaves_like 'an adapter context'
|
111
|
+
it_behaves_like 'transactions are not supported'
|
112
|
+
it_behaves_like 'client acks are not supported'
|
113
|
+
it_behaves_like 'subscriptions are not supported'
|
98
114
|
|
99
|
-
|
100
|
-
it_behaves_like 'transactions are not supported'
|
101
|
-
it_behaves_like 'client acks are not supported'
|
102
|
-
it_behaves_like 'subscriptions are not supported'
|
115
|
+
describe '#create_destination' do
|
103
116
|
|
104
|
-
|
117
|
+
context 'the resulting destination' do
|
118
|
+
let(:dest_name) { '/queue/stomp_destination_spec' }
|
119
|
+
subject(:destination) { adapter_context.create_destination(dest_name) }
|
105
120
|
|
106
|
-
|
107
|
-
let(:dest_name) { '/queue/stomp_destination_spec' }
|
108
|
-
subject(:destination) { adapter_context.create_destination(dest_name) }
|
121
|
+
it { is_expected.to be_a StompAdapter::Destination }
|
109
122
|
|
110
|
-
|
123
|
+
it_behaves_like 'a destination'
|
124
|
+
include_examples "doesn't support #message_count"
|
125
|
+
include_examples "doesn't support #consumer_count"
|
111
126
|
|
112
|
-
|
113
|
-
|
127
|
+
describe '#queue_path' do
|
128
|
+
it 'equals name' do
|
129
|
+
expect(subject.queue_path).to eq(subject.name)
|
130
|
+
end
|
114
131
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
132
|
+
context "when name does not start with '/'" do
|
133
|
+
let(:dest_name) { 'stomp_destination_spec' }
|
134
|
+
it 'prepends /queue' do
|
135
|
+
expect(subject.queue_path).to eq("/queue/#{dest_name}")
|
136
|
+
end
|
120
137
|
end
|
121
138
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
139
|
+
context "when the name does start with a '/'" do
|
140
|
+
let(:dest_name) { '/stomp_destination_spec' }
|
141
|
+
it 'equals the name' do
|
142
|
+
expect(subject.queue_path).to eq(dest_name)
|
143
|
+
end
|
126
144
|
end
|
127
145
|
end
|
128
146
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
147
|
+
describe 'pop_message' do
|
148
|
+
context 'when there is a message on the queue' do
|
149
|
+
let(:body) { 'Testing stomp pop_message' }
|
150
|
+
before do
|
151
|
+
destination.publish(body)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'returns the message' do
|
155
|
+
msg = destination.pop_message
|
156
|
+
expect(msg).to be_a MessageDriver::Adapters::StompAdapter::Message
|
157
|
+
expect(msg.body).to eq(body)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when the queue is empty' do
|
162
|
+
it 'returns nil' do
|
163
|
+
msg = destination.pop_message
|
164
|
+
expect(msg).to be_nil
|
165
|
+
end
|
133
166
|
end
|
134
167
|
end
|
135
168
|
end
|