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
data/spec/spec_helper.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
ENV['COMMAND_NAME'] = 'specs'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'test_lib', 'coverage')
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'test_lib', 'broker_config')
|
3
4
|
|
4
5
|
require 'message_driver'
|
5
6
|
|
6
|
-
|
7
|
+
BrokerConfig.setup_provider
|
7
8
|
|
8
|
-
Dir['./spec/support/**/*.rb'].sort.each {|f| require f}
|
9
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
9
10
|
|
10
11
|
RSpec.configure do |c|
|
11
|
-
c.
|
12
|
-
c.order = 'random'
|
12
|
+
c.order = :random
|
13
13
|
c.filter_run :focus
|
14
14
|
|
15
15
|
c.reporter.message("Acceptance Tests running with broker config: #{BrokerConfig.config}")
|
16
16
|
|
17
17
|
spec_logger = Logger.new(STDOUT).tap { |l| l.level = Logger::FATAL }
|
18
|
-
c.before(:
|
18
|
+
c.before(:example) do
|
19
19
|
MessageDriver.logger = spec_logger
|
20
20
|
end
|
21
21
|
|
22
|
-
c.after(:
|
22
|
+
c.after(:example) do
|
23
23
|
MessageDriver::Broker.reset
|
24
24
|
end
|
25
25
|
|
26
|
-
c.filter_run_excluding :no_ci if ENV['CI']=='true' && ENV['ADAPTER'] && ENV['ADAPTER'].start_with?('bunny')
|
26
|
+
c.filter_run_excluding :no_ci if ENV['CI'] == 'true' && ENV['ADAPTER'] && ENV['ADAPTER'].start_with?('bunny')
|
27
27
|
if c.inclusion_filter[:all_adapters] == true
|
28
28
|
BrokerConfig.unconfigured_adapters.each do |a|
|
29
29
|
c.filter_run_excluding a
|
@@ -32,4 +32,6 @@ RSpec.configure do |c|
|
|
32
32
|
else
|
33
33
|
c.run_all_when_everything_filtered = true
|
34
34
|
end
|
35
|
+
|
36
|
+
c.expose_dsl_globally = false
|
35
37
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
shared_examples 'client acks are supported' do
|
1
|
+
RSpec.shared_examples 'client acks are supported' do
|
2
2
|
describe '#supports_client_acks' do
|
3
3
|
it 'returns true' do
|
4
4
|
expect(subject.supports_client_acks?).to eq(true)
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
it {
|
9
|
-
it {
|
8
|
+
it { is_expected.to respond_to :ack_message }
|
9
|
+
it { is_expected.to respond_to :nack_message }
|
10
10
|
end
|
11
11
|
|
12
|
-
shared_examples 'client acks are not supported' do
|
12
|
+
RSpec.shared_examples 'client acks are not supported' do
|
13
13
|
describe '#supports_client_acks' do
|
14
14
|
it 'returns false' do
|
15
15
|
expect(subject.supports_client_acks?).to eq(false)
|
@@ -1,10 +1,12 @@
|
|
1
|
-
shared_examples 'an adapter context' do
|
2
|
-
it {
|
1
|
+
RSpec.shared_examples 'an adapter context' do
|
2
|
+
it { is_expected.to be_a MessageDriver::Adapters::ContextBase }
|
3
3
|
|
4
|
-
|
4
|
+
describe '#adapter' do
|
5
|
+
it { expect(subject.adapter).to be adapter }
|
6
|
+
end
|
5
7
|
|
6
8
|
it 'is initially valid' do
|
7
|
-
|
9
|
+
is_expected.to be_valid
|
8
10
|
end
|
9
11
|
|
10
12
|
describe '#invalidate' do
|
@@ -1,10 +1,12 @@
|
|
1
|
-
shared_examples 'a destination' do
|
2
|
-
|
1
|
+
RSpec.shared_examples 'a destination' do
|
2
|
+
describe '#adapter' do
|
3
|
+
it { expect(subject.adapter).to be adapter }
|
4
|
+
end
|
3
5
|
|
4
6
|
describe '#pop_message' do
|
5
7
|
let(:body) { 'The message body' }
|
6
|
-
let(:headers) { { 'foo' => 'bar', 'bar' => 'baz'} }
|
7
|
-
let(:properties) { {persistent: true, client_ack: true} }
|
8
|
+
let(:headers) { { 'foo' => 'bar', 'bar' => 'baz' } }
|
9
|
+
let(:properties) { { persistent: true, client_ack: true } }
|
8
10
|
|
9
11
|
before do
|
10
12
|
destination.publish(body, headers, properties)
|
@@ -13,30 +15,68 @@ shared_examples 'a destination' do
|
|
13
15
|
context 'the result' do
|
14
16
|
subject(:message) { destination.pop_message }
|
15
17
|
|
16
|
-
it {
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
it { is_expected.to be_a MessageDriver::Message::Base }
|
19
|
+
|
20
|
+
describe '#body' do
|
21
|
+
it { expect(subject.body).to eq(body) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#headers' do
|
25
|
+
it { expect(subject.headers).to include(headers) }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#properties' do
|
29
|
+
it { expect(subject.properties).not_to be_nil }
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
23
34
|
|
24
|
-
shared_examples "doesn't support #message_count" do
|
35
|
+
RSpec.shared_examples "doesn't support #message_count" do
|
25
36
|
describe '#message_count' do
|
26
37
|
it 'raises an error' do
|
27
|
-
expect
|
38
|
+
expect do
|
28
39
|
destination.message_count
|
29
|
-
|
40
|
+
end.to raise_error "#message_count is not supported by #{destination.class}"
|
30
41
|
end
|
31
42
|
end
|
32
43
|
end
|
33
44
|
|
34
|
-
shared_examples 'supports #message_count' do
|
45
|
+
RSpec.shared_examples 'supports #message_count' do
|
35
46
|
it "reports it's message_count" do
|
36
|
-
expect
|
47
|
+
expect do
|
37
48
|
destination.publish('msg1')
|
38
49
|
destination.publish('msg2')
|
39
50
|
pause_if_needed
|
40
|
-
|
51
|
+
end.to change { destination.message_count }.by(2)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
RSpec.shared_examples "doesn't support #consumer_count" do
|
56
|
+
describe '#consumer_count' do
|
57
|
+
it 'raises an error' do
|
58
|
+
expect do
|
59
|
+
destination.consumer_count
|
60
|
+
end.to raise_error "#consumer_count is not supported by #{destination.class}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
RSpec.shared_examples 'supports #consumer_count' do
|
66
|
+
describe '#consumer_count' do
|
67
|
+
it "reports it's consumer count" do
|
68
|
+
consumer1 = ->(_) {}
|
69
|
+
consumer2 = ->(_) {}
|
70
|
+
sub1 = nil
|
71
|
+
sub2 = nil
|
72
|
+
expect do
|
73
|
+
sub1 = destination.subscribe(&consumer1)
|
74
|
+
sub2 = destination.subscribe(&consumer2)
|
75
|
+
end.to change { destination.consumer_count }.by(2)
|
76
|
+
expect do
|
77
|
+
sub1.unsubscribe
|
78
|
+
sub2.unsubscribe
|
79
|
+
end.to change { destination.consumer_count }.by(-2)
|
80
|
+
end
|
41
81
|
end
|
42
82
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
shared_examples 'subscriptions are not supported' do
|
1
|
+
RSpec.shared_examples 'subscriptions are not supported' do
|
2
2
|
describe '#supports_subscriptions?' do
|
3
3
|
it 'returns false' do
|
4
4
|
expect(subject.supports_subscriptions?).to eq(false)
|
@@ -8,15 +8,15 @@ shared_examples 'subscriptions are not supported' do
|
|
8
8
|
describe '#subscribe' do
|
9
9
|
it 'raises an error' do
|
10
10
|
destination = double('destination')
|
11
|
-
consumer =
|
12
|
-
expect
|
11
|
+
consumer = ->(_) {}
|
12
|
+
expect do
|
13
13
|
subject.subscribe(destination, &consumer)
|
14
|
-
|
14
|
+
end.to raise_error "#subscribe is not supported by #{subject.adapter.class}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
shared_examples 'subscriptions are supported' do |subscription_type|
|
19
|
+
RSpec.shared_examples 'subscriptions are supported' do |subscription_type|
|
20
20
|
describe '#supports_subscriptions?' do
|
21
21
|
it 'returns true' do
|
22
22
|
expect(subject.supports_subscriptions?).to eq(true)
|
@@ -36,9 +36,7 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
36
36
|
|
37
37
|
describe '#subscribe' do
|
38
38
|
before do
|
39
|
-
if destination.respond_to? :purge
|
40
|
-
destination.purge
|
41
|
-
end
|
39
|
+
destination.purge if destination.respond_to? :purge
|
42
40
|
end
|
43
41
|
|
44
42
|
let(:subscription) { adapter_context.subscribe(destination, &consumer) }
|
@@ -53,18 +51,27 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
53
51
|
context 'the subscription' do
|
54
52
|
subject { subscription }
|
55
53
|
|
56
|
-
it {
|
57
|
-
it {
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
it { is_expected.to be_a MessageDriver::Subscription::Base }
|
55
|
+
it { is_expected.to be_a subscription_type }
|
56
|
+
|
57
|
+
describe '#adapter' do
|
58
|
+
it { expect(subject.adapter).to be adapter }
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#destination' do
|
62
|
+
it { expect(subject.destination).to be destination }
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#consumer' do
|
66
|
+
it { expect(subject.consumer).to be consumer }
|
67
|
+
end
|
61
68
|
|
62
69
|
describe '#unsubscribe' do
|
63
70
|
it "makes it so messages don't go to the consumer any more" do
|
64
71
|
subscription.unsubscribe
|
65
|
-
expect
|
72
|
+
expect do
|
66
73
|
destination.publish('should not be consumed')
|
67
|
-
|
74
|
+
end.to_not change { messages.size }
|
68
75
|
end
|
69
76
|
end
|
70
77
|
end
|
@@ -76,10 +83,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
76
83
|
end
|
77
84
|
|
78
85
|
it 'plays the messages into the consumer' do
|
79
|
-
expect
|
86
|
+
expect do
|
80
87
|
subscription
|
81
88
|
pause_if_needed
|
82
|
-
|
89
|
+
end.to change { messages.size }.from(0).to(2)
|
83
90
|
bodies = messages.map(&:body)
|
84
91
|
expect(bodies).to include(message1)
|
85
92
|
expect(bodies).to include(message2)
|
@@ -87,10 +94,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
87
94
|
|
88
95
|
it 'removes the messages from the queue' do
|
89
96
|
pause_if_needed
|
90
|
-
expect
|
97
|
+
expect do
|
91
98
|
subscription
|
92
99
|
pause_if_needed
|
93
|
-
|
100
|
+
end.to change { destination.message_count }.from(2).to(0)
|
94
101
|
end
|
95
102
|
end
|
96
103
|
|
@@ -100,12 +107,12 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
100
107
|
end
|
101
108
|
|
102
109
|
it 'consumers the message into the consumer instead of putting them on the queue' do
|
103
|
-
expect
|
104
|
-
expect
|
110
|
+
expect do
|
111
|
+
expect do
|
105
112
|
subject.publish(destination, message1)
|
106
113
|
pause_if_needed
|
107
|
-
|
108
|
-
|
114
|
+
end.to change { messages.length }.from(0).to(1)
|
115
|
+
end.to_not change { destination.message_count }
|
109
116
|
expect(messages[0].body).to eq(message1)
|
110
117
|
end
|
111
118
|
end
|
@@ -114,7 +121,7 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
114
121
|
let(:error) { RuntimeError.new('oh nos!') }
|
115
122
|
let(:consumer) do
|
116
123
|
lambda do |_|
|
117
|
-
|
124
|
+
fail error
|
118
125
|
end
|
119
126
|
end
|
120
127
|
|
@@ -125,10 +132,10 @@ shared_examples 'subscriptions are supported' do |subscription_type|
|
|
125
132
|
|
126
133
|
it 'keeps processing the messages' do
|
127
134
|
pause_if_needed
|
128
|
-
expect
|
135
|
+
expect do
|
129
136
|
subscription
|
130
137
|
pause_if_needed
|
131
|
-
|
138
|
+
end.to change { destination.message_count }.from(2).to(0)
|
132
139
|
end
|
133
140
|
|
134
141
|
context 'an error_handler is provided' do
|
@@ -1,4 +1,4 @@
|
|
1
|
-
shared_examples 'transactions are not supported' do
|
1
|
+
RSpec.shared_examples 'transactions are not supported' do
|
2
2
|
describe '#supports_transactions?' do
|
3
3
|
it 'returns false' do
|
4
4
|
expect(subject.supports_transactions?).to eq(false)
|
@@ -6,17 +6,17 @@ shared_examples 'transactions are not supported' do
|
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
shared_examples 'transactions are supported' do
|
9
|
+
RSpec.shared_examples 'transactions are supported' do
|
10
10
|
describe '#supports_transactions?' do
|
11
11
|
it 'returns true' do
|
12
12
|
expect(subject.supports_transactions?).to eq(true)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
it {
|
17
|
-
it {
|
18
|
-
it {
|
19
|
-
it {
|
16
|
+
it { is_expected.to respond_to :begin_transaction }
|
17
|
+
it { is_expected.to respond_to :commit_transaction }
|
18
|
+
it { is_expected.to respond_to :rollback_transaction }
|
19
|
+
it { is_expected.to respond_to :in_transaction? }
|
20
20
|
|
21
21
|
describe '#in_transaction?' do
|
22
22
|
it "returns false if you aren't in a transaction" do
|
@@ -26,18 +26,18 @@ shared_examples 'transactions are supported' do
|
|
26
26
|
|
27
27
|
it 'raises a MessageDriver::TransactionError error if you begin two transactions' do
|
28
28
|
subject.begin_transaction
|
29
|
-
expect
|
29
|
+
expect do
|
30
30
|
subject.begin_transaction
|
31
|
-
|
31
|
+
end.to raise_error MessageDriver::TransactionError
|
32
32
|
end
|
33
33
|
it 'raises a MessageDriver::TransactionError error if you commit outside of a transaction' do
|
34
|
-
expect
|
34
|
+
expect do
|
35
35
|
subject.commit_transaction
|
36
|
-
|
36
|
+
end.to raise_error MessageDriver::TransactionError
|
37
37
|
end
|
38
38
|
it 'raises a MessageDriver::TransactionError error if you rollback outside of a transaction' do
|
39
|
-
expect
|
39
|
+
expect do
|
40
40
|
subject.rollback_transaction
|
41
|
-
|
41
|
+
end.to raise_error MessageDriver::TransactionError
|
42
42
|
end
|
43
43
|
end
|
data/spec/support/utils.rb
CHANGED
@@ -1,55 +1,57 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
module MessageDriver
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
subject(:adapter) { TestAdapter.new({}) }
|
10
|
-
|
11
|
-
describe '#new_context' do
|
12
|
-
it 'raises an error' do
|
13
|
-
expect {
|
14
|
-
subject.new_context
|
15
|
-
}.to raise_error 'Must be implemented in subclass'
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
describe ContextBase do
|
20
|
-
class TestContext < ContextBase
|
3
|
+
module MessageDriver
|
4
|
+
module Adapters
|
5
|
+
RSpec.describe Base do
|
6
|
+
class TestAdapter < Base
|
7
|
+
def initialize(_configuration)
|
8
|
+
end
|
21
9
|
end
|
22
|
-
subject(:
|
23
|
-
|
24
|
-
it_behaves_like 'an adapter context'
|
25
|
-
it_behaves_like 'transactions are not supported'
|
26
|
-
it_behaves_like 'client acks are not supported'
|
27
|
-
it_behaves_like 'subscriptions are not supported'
|
10
|
+
subject(:adapter) { TestAdapter.new({}) }
|
28
11
|
|
29
|
-
describe '#
|
12
|
+
describe '#new_context' do
|
30
13
|
it 'raises an error' do
|
31
|
-
expect
|
32
|
-
subject.
|
33
|
-
|
14
|
+
expect do
|
15
|
+
subject.new_context
|
16
|
+
end.to raise_error 'Must be implemented in subclass'
|
34
17
|
end
|
35
18
|
end
|
36
19
|
|
37
|
-
describe
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
20
|
+
describe ContextBase do
|
21
|
+
class TestContext < ContextBase
|
22
|
+
end
|
23
|
+
subject(:adapter_context) { TestContext.new(adapter) }
|
24
|
+
|
25
|
+
it_behaves_like 'an adapter context'
|
26
|
+
it_behaves_like 'transactions are not supported'
|
27
|
+
it_behaves_like 'client acks are not supported'
|
28
|
+
it_behaves_like 'subscriptions are not supported'
|
29
|
+
|
30
|
+
describe '#create_destination' do
|
31
|
+
it 'raises an error' do
|
32
|
+
expect do
|
33
|
+
subject.create_destination('foo')
|
34
|
+
end.to raise_error 'Must be implemented in subclass'
|
35
|
+
end
|
42
36
|
end
|
43
|
-
end
|
44
37
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
38
|
+
describe '#publish' do
|
39
|
+
it 'raises an error' do
|
40
|
+
expect do
|
41
|
+
subject.publish(:destination, foo: 'bar')
|
42
|
+
end.to raise_error 'Must be implemented in subclass'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#pop_message' do
|
47
|
+
it 'raises an error' do
|
48
|
+
expect do
|
49
|
+
subject.pop_message(:destination)
|
50
|
+
end.to raise_error 'Must be implemented in subclass'
|
51
|
+
end
|
50
52
|
end
|
51
|
-
end
|
52
53
|
|
54
|
+
end
|
53
55
|
end
|
54
56
|
end
|
55
57
|
end
|